commit 44f756301426f0b7f111b054a6a5111551a82c45 Author: fspecii Date: Wed Feb 4 03:09:38 2026 +0200 Initial commit: ACE-Step UI - Open source music generation interface diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4642203 --- /dev/null +++ b/.env.example @@ -0,0 +1,25 @@ +# ACE-Step UI Configuration + +# Server +PORT=3001 +NODE_ENV=development + +# Database (SQLite) +DATABASE_PATH=./data/acestep.db + +# ACE-Step API (local) +ACESTEP_API_URL=http://localhost:8001 + +# Storage +AUDIO_DIR=./public/audio + +# Frontend +FRONTEND_URL=http://localhost:5173 +VITE_API_URL=http://localhost:3001 + +# JWT Secret (for local session management) +JWT_SECRET=ace-step-ui-local-secret + +# Optional: Pexels API Key (for video backgrounds) +# Get a free API key at https://www.pexels.com/api/ +PEXELS_API_KEY= diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..21a63c9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,92 @@ +# Dependencies +node_modules/ +server/node_modules/ + +# Build outputs +dist/ +dist-ssr/ +build/ +*.tsbuildinfo + +# Environment files +.env +.env.local +.env.*.local +*.local +server/.env + +# Database (SQLite) +server/data/*.db +server/data/*.db-shm +server/data/*.db-wal +!server/data/.gitkeep + +# Generated audio files +server/public/audio/*.mp3 +server/public/audio/*.flac +server/public/audio/*.wav +server/public/audio/*/ +!server/public/audio/.gitkeep + +# Reference tracks (user uploads) +server/public/audio/reference-tracks/* +!server/public/audio/reference-tracks/.gitkeep + +# User uploads +server/public/uploads/ + +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# Editor/IDE +.vscode/* +!.vscode/extensions.json +.idea/ +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +*.swp +*.swo +*~ + +# OS files +.DS_Store +Thumbs.db + +# Vite cache +.vite/ + +# Cache +.cache/ +*.cache + +# Test coverage +coverage/ + +# Temporary files +tmp/ +temp/ +*.tmp + +# Demucs working files +server/public/demucs-web/output/ + +# Python +__pycache__/ +*.py[cod] +.venv/ + +# Misc +ComfyUI/ +comfyui/ + +# External editors (wavacity is 184MB - clone separately if needed) +wavacity-editor/ diff --git a/App.tsx b/App.tsx new file mode 100644 index 0000000..493acce --- /dev/null +++ b/App.tsx @@ -0,0 +1,1095 @@ +import React, { useState, useEffect, useRef, useCallback } from 'react'; +import { Sidebar } from './components/Sidebar'; +import { CreatePanel } from './components/CreatePanel'; +import { SongList } from './components/SongList'; +import { RightSidebar } from './components/RightSidebar'; +import { Player } from './components/Player'; +import { LibraryView } from './components/LibraryView'; +import { CreatePlaylistModal, AddToPlaylistModal } from './components/PlaylistModals'; +import { VideoGeneratorModal } from './components/VideoGeneratorModal'; +import { UsernameModal } from './components/UsernameModal'; +import { UserProfile } from './components/UserProfile'; +import { SettingsModal } from './components/SettingsModal'; +import { SongProfile } from './components/SongProfile'; +import { Song, GenerationParams, View, Playlist } from './types'; +import { generateApi, songsApi, playlistsApi, getAudioUrl } from './services/api'; +import { useAuth } from './context/AuthContext'; +import { useResponsive } from './context/ResponsiveContext'; +import { List } from 'lucide-react'; +import { PlaylistDetail } from './components/PlaylistDetail'; +import { Toast, ToastType } from './components/Toast'; +import { SearchPage } from './components/SearchPage'; + + +export default function App() { + // Responsive + const { isMobile, isDesktop } = useResponsive(); + + // Auth + const { user, token, isAuthenticated, isLoading: authLoading, setupUser, logout } = useAuth(); + const [showUsernameModal, setShowUsernameModal] = useState(false); + // Track multiple concurrent generation jobs + const activeJobsRef = useRef }>>(new Map()); + const [activeJobCount, setActiveJobCount] = useState(0); + + // Theme State + const [theme, setTheme] = useState<'dark' | 'light'>(() => { + const stored = localStorage.getItem('theme'); + if (stored === 'dark' || stored === 'light') return stored; + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + }); + + // Navigation State - default to create view + const [currentView, setCurrentView] = useState('create'); + + // Content State + const [songs, setSongs] = useState([]); + const [playlists, setPlaylists] = useState([]); + const [likedSongIds, setLikedSongIds] = useState>(new Set()); + const [playQueue, setPlayQueue] = useState([]); + const [queueIndex, setQueueIndex] = useState(-1); + + // Selection State + const [currentSong, setCurrentSong] = useState(null); + const [selectedSong, setSelectedSong] = useState(null); + const [selectedPlaylist, setSelectedPlaylist] = useState(null); + + // Player State + const [isPlaying, setIsPlaying] = useState(false); + const [currentTime, setCurrentTime] = useState(0); + const [duration, setDuration] = useState(0); + const [volume, setVolume] = useState(0.8); + const [isShuffle, setIsShuffle] = useState(false); + const [repeatMode, setRepeatMode] = useState<'none' | 'all' | 'one'>('all'); + + // UI State + const [isGenerating, setIsGenerating] = useState(false); + const [showRightSidebar, setShowRightSidebar] = useState(true); + + // Mobile UI Toggle + const [mobileShowList, setMobileShowList] = useState(false); + + // Modals + const [isCreatePlaylistModalOpen, setIsCreatePlaylistModalOpen] = useState(false); + const [isAddToPlaylistModalOpen, setIsAddToPlaylistModalOpen] = useState(false); + const [songToAddToPlaylist, setSongToAddToPlaylist] = useState(null); + + // Video Modal + const [isVideoModalOpen, setIsVideoModalOpen] = useState(false); + const [songForVideo, setSongForVideo] = useState(null); + + // Settings Modal + const [showSettingsModal, setShowSettingsModal] = useState(false); + + // Profile View + const [viewingUsername, setViewingUsername] = useState(null); + + // Song View + const [viewingSongId, setViewingSongId] = useState(null); + + // Playlist View + const [viewingPlaylistId, setViewingPlaylistId] = useState(null); + + // Reuse State + const [reuseData, setReuseData] = useState<{ song: Song, timestamp: number } | null>(null); + + const audioRef = useRef(null); + const pendingSeekRef = useRef(null); + const playNextRef = useRef<() => void>(() => {}); + + // Mobile Details Modal State + const [showMobileDetails, setShowMobileDetails] = useState(false); + + // Toast State + const [toast, setToast] = useState<{ message: string; type: ToastType; isVisible: boolean }>({ + message: '', + type: 'success', + isVisible: false, + }); + + const showToast = (message: string, type: ToastType = 'success') => { + setToast({ message, type, isVisible: true }); + }; + + const closeToast = () => { + setToast(prev => ({ ...prev, isVisible: false })); + }; + + // Show username modal if not authenticated and not loading + useEffect(() => { + if (!authLoading && !isAuthenticated) { + setShowUsernameModal(true); + } + }, [authLoading, isAuthenticated]); + + // Load Playlists + useEffect(() => { + if (token) { + playlistsApi.getMyPlaylists(token) + .then(res => setPlaylists(res.playlists)) + .catch(err => console.error('Failed to load playlists', err)); + } else { + setPlaylists([]); + } + }, [token]); + + // Cleanup active jobs on unmount + useEffect(() => { + return () => { + // Clear all polling intervals when component unmounts + activeJobsRef.current.forEach(({ pollInterval }) => { + clearInterval(pollInterval); + }); + activeJobsRef.current.clear(); + }; + }, []); + + const handleShowDetails = (song: Song) => { + setSelectedSong(song); + setShowMobileDetails(true); + }; + + // Reuse Handler + const handleReuse = (song: Song) => { + setReuseData({ song, timestamp: Date.now() }); + setCurrentView('create'); + setMobileShowList(false); + }; + + // Song Update Handler + const handleSongUpdate = (updatedSong: Song) => { + setSongs(prev => prev.map(s => s.id === updatedSong.id ? updatedSong : s)); + if (selectedSong?.id === updatedSong.id) { + setSelectedSong(updatedSong); + } + }; + + // Navigate to Profile Handler + const handleNavigateToProfile = (username: string) => { + setViewingUsername(username); + setCurrentView('profile'); + window.history.pushState({}, '', `/@${username}`); + }; + + // Back from Profile Handler + const handleBackFromProfile = () => { + setViewingUsername(null); + setCurrentView('create'); + window.history.pushState({}, '', '/'); + }; + + // Navigate to Song Handler + const handleNavigateToSong = (songId: string) => { + setViewingSongId(songId); + setCurrentView('song'); + window.history.pushState({}, '', `/song/${songId}`); + }; + + // Back from Song Handler + const handleBackFromSong = () => { + setViewingSongId(null); + setCurrentView('create'); + window.history.pushState({}, '', '/'); + }; + + // Theme Effect + useEffect(() => { + localStorage.setItem('theme', theme); + if (theme === 'dark') { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + }, [theme]); + + const toggleTheme = () => { + setTheme(prev => prev === 'dark' ? 'light' : 'dark'); + }; + + // URL Routing Effect + useEffect(() => { + const handleUrlChange = () => { + const path = window.location.pathname; + const params = new URLSearchParams(window.location.search); + + // Handle ?song= query parameter + const songParam = params.get('song'); + if (songParam) { + setViewingSongId(songParam); + setCurrentView('song'); + window.history.replaceState({}, '', `/song/${songParam}`); + return; + } + + if (path === '/create' || path === '/') { + setCurrentView('create'); + setMobileShowList(false); + } else if (path === '/library') { + setCurrentView('library'); + } else if (path.startsWith('/@')) { + const username = path.substring(2); + if (username) { + setViewingUsername(username); + setCurrentView('profile'); + } + } else if (path.startsWith('/song/')) { + const songId = path.substring(6); + if (songId) { + setViewingSongId(songId); + setCurrentView('song'); + } + } else if (path.startsWith('/playlist/')) { + const playlistId = path.substring(10); + if (playlistId) { + setViewingPlaylistId(playlistId); + setCurrentView('playlist'); + } + } else if (path === '/search') { + setCurrentView('search'); + } + }; + + handleUrlChange(); + + window.addEventListener('popstate', handleUrlChange); + return () => window.removeEventListener('popstate', handleUrlChange); + }, []); + + // Load Songs Effect + useEffect(() => { + if (!isAuthenticated || !token) return; + + const loadSongs = async () => { + try { + const [mySongsRes, likedSongsRes] = await Promise.all([ + songsApi.getMySongs(token), + songsApi.getLikedSongs(token) + ]); + + const mapSong = (s: any): Song => ({ + id: s.id, + title: s.title, + lyrics: s.lyrics, + style: s.style, + coverUrl: `https://picsum.photos/seed/${s.id}/400/400`, + duration: s.duration && s.duration > 0 ? `${Math.floor(s.duration / 60)}:${String(Math.floor(s.duration % 60)).padStart(2, '0')}` : '0:00', + createdAt: new Date(s.created_at || s.createdAt), + tags: s.tags || [], + audioUrl: getAudioUrl(s.audio_url, s.id), + isPublic: s.is_public, + likeCount: s.like_count || 0, + viewCount: s.view_count || 0, + userId: s.user_id, + creator: s.creator, + }); + + const mySongs = mySongsRes.songs.map(mapSong); + const likedSongs = likedSongsRes.songs.map(mapSong); + + const songsMap = new Map(); + [...mySongs, ...likedSongs].forEach(s => songsMap.set(s.id, s)); + + // Preserve any generating songs (temp songs) + setSongs(prev => { + const generatingSongs = prev.filter(s => s.isGenerating); + const loadedSongs = Array.from(songsMap.values()); + return [...generatingSongs, ...loadedSongs]; + }); + + const likedIds = new Set(likedSongs.map(s => s.id)); + setLikedSongIds(likedIds); + + } catch (error) { + console.error('Failed to load songs:', error); + } + }; + + loadSongs(); + }, [isAuthenticated, token]); + + // Player Logic + const getActiveQueue = (song?: Song) => { + if (playQueue.length > 0) return playQueue; + if (song && songs.some(s => s.id === song.id)) return songs; + return songs; + }; + + const playNext = useCallback(() => { + if (!currentSong) return; + const queue = getActiveQueue(currentSong); + if (queue.length === 0) return; + + const currentIndex = queueIndex >= 0 && queue[queueIndex]?.id === currentSong.id + ? queueIndex + : queue.findIndex(s => s.id === currentSong.id); + if (currentIndex === -1) return; + + if (repeatMode === 'one') { + if (audioRef.current) { + audioRef.current.currentTime = 0; + audioRef.current.play(); + } + return; + } + + let nextIndex; + if (isShuffle) { + do { + nextIndex = Math.floor(Math.random() * queue.length); + } while (queue.length > 1 && nextIndex === currentIndex); + } else { + nextIndex = (currentIndex + 1) % queue.length; + } + + const nextSong = queue[nextIndex]; + setQueueIndex(nextIndex); + setCurrentSong(nextSong); + setIsPlaying(true); + }, [currentSong, queueIndex, isShuffle, repeatMode, playQueue, songs]); + + const playPrevious = useCallback(() => { + if (!currentSong) return; + const queue = getActiveQueue(currentSong); + if (queue.length === 0) return; + + const currentIndex = queueIndex >= 0 && queue[queueIndex]?.id === currentSong.id + ? queueIndex + : queue.findIndex(s => s.id === currentSong.id); + if (currentIndex === -1) return; + + if (currentTime > 3) { + if (audioRef.current) audioRef.current.currentTime = 0; + return; + } + + let prevIndex = (currentIndex - 1 + queue.length) % queue.length; + if (isShuffle) { + prevIndex = Math.floor(Math.random() * queue.length); + } + + const prevSong = queue[prevIndex]; + setQueueIndex(prevIndex); + setCurrentSong(prevSong); + setIsPlaying(true); + }, [currentSong, queueIndex, currentTime, isShuffle, playQueue, songs]); + + useEffect(() => { + playNextRef.current = playNext; + }, [playNext]); + + // Audio Setup + useEffect(() => { + audioRef.current = new Audio(); + audioRef.current.crossOrigin = "anonymous"; + const audio = audioRef.current; + audio.volume = volume; + + const onTimeUpdate = () => setCurrentTime(audio.currentTime); + const applyPendingSeek = () => { + if (pendingSeekRef.current === null) return; + if (audio.seekable.length === 0) return; + const target = pendingSeekRef.current; + const safeTarget = Number.isFinite(audio.duration) + ? Math.min(Math.max(target, 0), audio.duration) + : Math.max(target, 0); + audio.currentTime = safeTarget; + setCurrentTime(safeTarget); + pendingSeekRef.current = null; + }; + + const onLoadedMetadata = () => { + setDuration(audio.duration); + applyPendingSeek(); + }; + + const onCanPlay = () => { + applyPendingSeek(); + }; + + const onProgress = () => { + applyPendingSeek(); + }; + + const onEnded = () => { + playNextRef.current(); + }; + + const onError = (e: Event) => { + if (audio.error && audio.error.code !== 1) { + console.error("Audio playback error:", audio.error); + if (audio.error.code === 4) { + showToast('This song is no longer available.', 'error'); + } else { + showToast('Unable to play this song.', 'error'); + } + } + setIsPlaying(false); + }; + + audio.addEventListener('timeupdate', onTimeUpdate); + audio.addEventListener('loadedmetadata', onLoadedMetadata); + audio.addEventListener('canplay', onCanPlay); + audio.addEventListener('progress', onProgress); + audio.addEventListener('ended', onEnded); + audio.addEventListener('error', onError); + + return () => { + audio.pause(); + audio.removeEventListener('timeupdate', onTimeUpdate); + audio.removeEventListener('loadedmetadata', onLoadedMetadata); + audio.removeEventListener('canplay', onCanPlay); + audio.removeEventListener('progress', onProgress); + audio.removeEventListener('ended', onEnded); + audio.removeEventListener('error', onError); + }; + }, []); + + // Handle Playback State + useEffect(() => { + const audio = audioRef.current; + if (!audio || !currentSong?.audioUrl) return; + + const playAudio = async () => { + try { + await audio.play(); + } catch (err) { + if (err instanceof Error && err.name !== 'AbortError') { + console.error("Playback failed:", err); + if (err.name === 'NotSupportedError') { + showToast('This song is no longer available.', 'error'); + } + setIsPlaying(false); + } + } + }; + + if (audio.src !== currentSong.audioUrl) { + audio.src = currentSong.audioUrl; + audio.load(); + if (isPlaying) playAudio(); + } else { + if (isPlaying) playAudio(); + else audio.pause(); + } + }, [currentSong, isPlaying]); + + // Handle Volume + useEffect(() => { + if (audioRef.current) { + audioRef.current.volume = volume; + } + }, [volume]); + + // Helper to cleanup a job and check if all jobs are done + const cleanupJob = useCallback((jobId: string, tempId: string) => { + const jobData = activeJobsRef.current.get(jobId); + if (jobData) { + clearInterval(jobData.pollInterval); + activeJobsRef.current.delete(jobId); + } + + // Remove temp song + setSongs(prev => prev.filter(s => s.id !== tempId)); + + // Update active job count + setActiveJobCount(activeJobsRef.current.size); + + // If no more active jobs, set isGenerating to false + if (activeJobsRef.current.size === 0) { + setIsGenerating(false); + } + }, []); + + // Refresh songs list (called when any job completes successfully) + const refreshSongsList = useCallback(async () => { + if (!token) return; + try { + const response = await songsApi.getMySongs(token); + const loadedSongs: Song[] = response.songs.map(s => ({ + id: s.id, + title: s.title, + lyrics: s.lyrics, + style: s.style, + coverUrl: `https://picsum.photos/seed/${s.id}/400/400`, + duration: s.duration && s.duration > 0 ? `${Math.floor(s.duration / 60)}:${String(Math.floor(s.duration % 60)).padStart(2, '0')}` : '0:00', + createdAt: new Date(s.created_at), + tags: s.tags || [], + audioUrl: getAudioUrl(s.audio_url, s.id), + isPublic: s.is_public, + likeCount: s.like_count || 0, + viewCount: s.view_count || 0, + userId: s.user_id, + creator: s.creator, + })); + + // Preserve any generating songs that aren't in the loaded list + setSongs(prev => { + const generatingSongs = prev.filter(s => s.isGenerating); + const mergedSongs = [...generatingSongs]; + for (const song of loadedSongs) { + if (!mergedSongs.some(s => s.id === song.id)) { + mergedSongs.push(song); + } + } + // Sort by creation date, newest first + return mergedSongs.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()); + }); + } catch (error) { + console.error('Failed to refresh songs:', error); + } + }, [token]); + + // Handlers + const handleGenerate = async (params: GenerationParams) => { + if (!isAuthenticated || !token) { + setShowUsernameModal(true); + return; + } + + setIsGenerating(true); + setCurrentView('create'); + setMobileShowList(false); + + // Create unique temp ID for this job + const tempId = `temp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + const tempSong: Song = { + id: tempId, + title: params.title || 'Generating...', + lyrics: '', + style: params.style, + coverUrl: 'https://picsum.photos/200/200?blur=10', + duration: '--:--', + createdAt: new Date(), + isGenerating: true, + tags: params.customMode ? ['custom'] : ['simple'], + isPublic: true + }; + + setSongs(prev => [tempSong, ...prev]); + setSelectedSong(tempSong); + setShowRightSidebar(true); + + try { + const job = await generateApi.startGeneration({ + customMode: params.customMode, + songDescription: params.songDescription, + lyrics: params.lyrics, + style: params.style, + title: params.title, + instrumental: params.instrumental, + vocalLanguage: params.vocalLanguage, + duration: params.duration, + bpm: params.bpm, + keyScale: params.keyScale, + timeSignature: params.timeSignature, + inferenceSteps: params.inferenceSteps, + guidanceScale: params.guidanceScale, + batchSize: params.batchSize, + randomSeed: params.randomSeed, + seed: params.seed, + thinking: params.thinking, + audioFormat: params.audioFormat, + inferMethod: params.inferMethod, + shift: params.shift, + lmTemperature: params.lmTemperature, + lmCfgScale: params.lmCfgScale, + lmTopK: params.lmTopK, + lmTopP: params.lmTopP, + lmNegativePrompt: params.lmNegativePrompt, + referenceAudioUrl: params.referenceAudioUrl, + sourceAudioUrl: params.sourceAudioUrl, + audioCodes: params.audioCodes, + repaintingStart: params.repaintingStart, + repaintingEnd: params.repaintingEnd, + instruction: params.instruction, + audioCoverStrength: params.audioCoverStrength, + taskType: params.taskType, + useAdg: params.useAdg, + cfgIntervalStart: params.cfgIntervalStart, + cfgIntervalEnd: params.cfgIntervalEnd, + customTimesteps: params.customTimesteps, + useCotMetas: params.useCotMetas, + useCotCaption: params.useCotCaption, + useCotLanguage: params.useCotLanguage, + autogen: params.autogen, + constrainedDecodingDebug: params.constrainedDecodingDebug, + allowLmBatch: params.allowLmBatch, + getScores: params.getScores, + getLrc: params.getLrc, + scoreScale: params.scoreScale, + lmBatchChunkSize: params.lmBatchChunkSize, + trackName: params.trackName, + completeTrackClasses: params.completeTrackClasses, + isFormatCaption: params.isFormatCaption, + }, token); + + // Poll for completion - each job has its own polling interval + const pollInterval = setInterval(async () => { + try { + const status = await generateApi.getStatus(job.jobId, token); + + // Update queue position on the temp song + setSongs(prev => prev.map(s => { + if (s.id === tempId) { + return { + ...s, + queuePosition: status.status === 'queued' ? status.queuePosition : undefined, + }; + } + return s; + })); + + if (status.status === 'succeeded' && status.result) { + cleanupJob(job.jobId, tempId); + await refreshSongsList(); + + if (window.innerWidth < 768) { + setMobileShowList(true); + } + } else if (status.status === 'failed') { + cleanupJob(job.jobId, tempId); + console.error(`Job ${job.jobId} failed:`, status.error); + showToast(`Generation failed: ${status.error || 'Unknown error'}`, 'error'); + } + } catch (pollError) { + console.error(`Polling error for job ${job.jobId}:`, pollError); + cleanupJob(job.jobId, tempId); + } + }, 2000); + + // Track this job + activeJobsRef.current.set(job.jobId, { tempId, pollInterval }); + setActiveJobCount(activeJobsRef.current.size); + + // Timeout after 10 minutes + setTimeout(() => { + if (activeJobsRef.current.has(job.jobId)) { + console.warn(`Job ${job.jobId} timed out`); + cleanupJob(job.jobId, tempId); + showToast('Generation timed out', 'error'); + } + }, 600000); + + } catch (e) { + console.error('Generation error:', e); + setSongs(prev => prev.filter(s => s.id !== tempId)); + + // Only set isGenerating to false if no other jobs are running + if (activeJobsRef.current.size === 0) { + setIsGenerating(false); + } + showToast('Generation failed. Please try again.', 'error'); + } + }; + + const togglePlay = () => { + if (!currentSong) return; + setIsPlaying(!isPlaying); + }; + + const playSong = (song: Song, list?: Song[]) => { + const nextQueue = list && list.length > 0 + ? list + : (playQueue.length > 0 && playQueue.some(s => s.id === song.id)) + ? playQueue + : (songs.some(s => s.id === song.id) ? songs : [song]); + const nextIndex = nextQueue.findIndex(s => s.id === song.id); + setPlayQueue(nextQueue); + setQueueIndex(nextIndex); + + if (currentSong?.id !== song.id) { + const updatedSong = { ...song, viewCount: (song.viewCount || 0) + 1 }; + setCurrentSong(updatedSong); + setSelectedSong(updatedSong); + setIsPlaying(true); + setSongs(prev => prev.map(s => s.id === song.id ? updatedSong : s)); + songsApi.trackPlay(song.id, token).catch(err => console.error('Failed to track play:', err)); + } else { + togglePlay(); + } + if (currentSong?.id === song.id) { + setSelectedSong(song); + } + setShowRightSidebar(true); + }; + + const handleSeek = (time: number) => { + const audio = audioRef.current; + if (!audio) return; + if (Number.isNaN(audio.duration) || audio.readyState < 1 || audio.seekable.length === 0) { + pendingSeekRef.current = time; + return; + } + audio.currentTime = time; + setCurrentTime(time); + }; + + const toggleLike = async (songId: string) => { + if (!token) return; + + const isLiked = likedSongIds.has(songId); + + // Optimistic update + setLikedSongIds(prev => { + const next = new Set(prev); + if (isLiked) next.delete(songId); + else next.add(songId); + return next; + }); + + setSongs(prev => prev.map(s => { + if (s.id === songId) { + const newCount = (s.likeCount || 0) + (isLiked ? -1 : 1); + return { ...s, likeCount: Math.max(0, newCount) }; + } + return s; + })); + + if (selectedSong?.id === songId) { + setSelectedSong(prev => prev ? { + ...prev, + likeCount: Math.max(0, (prev.likeCount || 0) + (isLiked ? -1 : 1)) + } : null); + } + + // Persist to database + try { + await songsApi.toggleLike(songId, token); + } catch (error) { + console.error('Failed to toggle like:', error); + // Revert on error + setLikedSongIds(prev => { + const next = new Set(prev); + if (isLiked) next.add(songId); + else next.delete(songId); + return next; + }); + } + }; + + const createPlaylist = async (name: string, description: string) => { + if (!token) return; + try { + const res = await playlistsApi.create(name, description, true, token); + setPlaylists(prev => [res.playlist, ...prev]); + + if (songToAddToPlaylist) { + await playlistsApi.addSong(res.playlist.id, songToAddToPlaylist.id, token); + setSongToAddToPlaylist(null); + playlistsApi.getMyPlaylists(token).then(r => setPlaylists(r.playlists)); + } + showToast('Playlist created successfully!'); + } catch (error) { + console.error('Create playlist error:', error); + showToast('Failed to create playlist', 'error'); + } + }; + + const openAddToPlaylistModal = (song: Song) => { + setSongToAddToPlaylist(song); + setIsAddToPlaylistModalOpen(true); + }; + + const addSongToPlaylist = async (playlistId: string) => { + if (!songToAddToPlaylist || !token) return; + try { + await playlistsApi.addSong(playlistId, songToAddToPlaylist.id, token); + setSongToAddToPlaylist(null); + showToast('Song added to playlist'); + playlistsApi.getMyPlaylists(token).then(r => setPlaylists(r.playlists)); + } catch (error) { + console.error('Add song error:', error); + showToast('Failed to add song to playlist', 'error'); + } + }; + + const handleNavigateToPlaylist = (playlistId: string) => { + setViewingPlaylistId(playlistId); + setCurrentView('playlist'); + window.history.pushState({}, '', `/playlist/${playlistId}`); + }; + + const handleBackFromPlaylist = () => { + setViewingPlaylistId(null); + setCurrentView('library'); + window.history.pushState({}, '', '/library'); + }; + + const openVideoGenerator = (song: Song) => { + if (isPlaying) { + setIsPlaying(false); + if (audioRef.current) audioRef.current.pause(); + } + setSongForVideo(song); + setIsVideoModalOpen(true); + }; + + // Handle username setup + const handleUsernameSubmit = async (username: string) => { + await setupUser(username); + setShowUsernameModal(false); + }; + + // Render Layout Logic + const renderContent = () => { + switch (currentView) { + case 'library': + return ( + likedSongIds.has(s.id))} + playlists={playlists} + onPlaySong={playSong} + onCreatePlaylist={() => { + setSongToAddToPlaylist(null); + setIsCreatePlaylistModalOpen(true); + }} + onSelectPlaylist={(p) => handleNavigateToPlaylist(p.id)} + /> + ); + + case 'profile': + if (!viewingUsername) return null; + return ( + + ); + + case 'playlist': + if (!viewingPlaylistId) return null; + return ( + { + setSelectedSong(s); + setShowRightSidebar(true); + }} + onNavigateToProfile={handleNavigateToProfile} + /> + ); + + case 'song': + if (!viewingSongId) return null; + return ( + + ); + + case 'search': + return ( + + ); + + case 'create': + default: + return ( +
+ {/* Create Panel */} +
+ +
+ + {/* Song List */} +
+ { + setSelectedSong(s); + setShowRightSidebar(true); + }} + onToggleLike={toggleLike} + onAddToPlaylist={openAddToPlaylistModal} + onOpenVideo={openVideoGenerator} + onShowDetails={handleShowDetails} + onNavigateToProfile={handleNavigateToProfile} + onReusePrompt={handleReuse} + /> +
+ + {/* Right Sidebar */} + {showRightSidebar && ( +
+ setShowRightSidebar(false)} + onOpenVideo={() => selectedSong && openVideoGenerator(selectedSong)} + onReuse={handleReuse} + onSongUpdate={handleSongUpdate} + onNavigateToProfile={handleNavigateToProfile} + onNavigateToSong={handleNavigateToSong} + isLiked={selectedSong ? likedSongIds.has(selectedSong.id) : false} + onToggleLike={toggleLike} + /> +
+ )} + + {/* Mobile Toggle Button */} +
+ +
+
+ ); + } + }; + + return ( +
+
+ { + setCurrentView(v); + if (v === 'create') { + setMobileShowList(false); + window.history.pushState({}, '', '/'); + } else if (v === 'library') { + window.history.pushState({}, '', '/library'); + } else if (v === 'search') { + window.history.pushState({}, '', '/search'); + } + }} + theme={theme} + onToggleTheme={toggleTheme} + user={user} + onLogin={() => setShowUsernameModal(true)} + onLogout={logout} + onOpenSettings={() => setShowSettingsModal(true)} + /> + +
+ {renderContent()} +
+
+ + setIsShuffle(!isShuffle)} + repeatMode={repeatMode} + onToggleRepeat={() => setRepeatMode(prev => prev === 'none' ? 'all' : prev === 'all' ? 'one' : 'none')} + isLiked={currentSong ? likedSongIds.has(currentSong.id) : false} + onToggleLike={() => currentSong && toggleLike(currentSong.id)} + onNavigateToSong={handleNavigateToSong} + onOpenVideo={() => currentSong && openVideoGenerator(currentSong)} + onReusePrompt={() => currentSong && handleReuse(currentSong)} + onAddToPlaylist={() => currentSong && openAddToPlaylistModal(currentSong)} + /> + + setIsCreatePlaylistModalOpen(false)} + onCreate={createPlaylist} + /> + setIsAddToPlaylistModalOpen(false)} + playlists={playlists} + onSelect={addSongToPlaylist} + onCreateNew={() => { + setIsAddToPlaylistModalOpen(false); + setIsCreatePlaylistModalOpen(true); + }} + /> + + setIsVideoModalOpen(false)} + song={songForVideo} + /> + + setShowSettingsModal(false)} + theme={theme} + onToggleTheme={toggleTheme} + onNavigateToProfile={handleNavigateToProfile} + /> + + {/* Mobile Details Modal */} + {showMobileDetails && selectedSong && ( +
+
setShowMobileDetails(false)} + /> +
+ setShowMobileDetails(false)} + onOpenVideo={() => selectedSong && openVideoGenerator(selectedSong)} + onReuse={handleReuse} + onSongUpdate={handleSongUpdate} + onNavigateToProfile={handleNavigateToProfile} + onNavigateToSong={handleNavigateToSong} + isLiked={selectedSong ? likedSongIds.has(selectedSong.id) : false} + onToggleLike={toggleLike} + /> +
+
+ )} +
+ ); +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..ddd6753 --- /dev/null +++ b/README.md @@ -0,0 +1,197 @@ +# ACE-Step UI + +A local-first web UI for [ACE-Step 1.5](https://github.com/ace-step/ACE-Step) AI music generation. + +![ACE-Step UI](https://img.shields.io/badge/ACE--Step-1.5-pink) +![License](https://img.shields.io/badge/license-MIT-blue) + +## Features + +- Generate music with text prompts and lyrics +- Simple and Custom generation modes +- Instrumental and vocal track support +- Audio editor with waveform visualization +- Stem extraction (vocals, drums, bass, other) +- Video generator with Pexels backgrounds +- Local SQLite database (no cloud required) +- Playlist management +- Beautiful gradient album covers (no internet needed) + +## Requirements + +- **Node.js** 18+ +- **Python** 3.10+ (3.11 recommended) +- **NVIDIA GPU** with 8GB+ VRAM (12GB+ recommended) +- **FFmpeg** and **FFprobe** (for audio processing) +- [uv](https://github.com/astral-sh/uv) package manager (recommended for Python) + +## Installation + +### 1. Install ACE-Step + +```bash +# Clone ACE-Step +git clone https://github.com/ace-step/ACE-Step +cd ACE-Step + +# Create virtual environment and install +uv venv +uv pip install -e . + +# Download the model (first run will download automatically, or manually): +# The model will be downloaded to ~/.cache/huggingface/ + +cd .. +``` + +### 2. Install ACE-Step UI + +```bash +# Clone this repository +git clone https://github.com/your-org/ace-step-ui +cd ace-step-ui + +# Run setup script +./setup.sh +``` + +Or manually: + +```bash +# Install frontend dependencies +npm install + +# Install server dependencies +cd server +npm install +cd .. + +# Copy environment file +cp server/.env.example server/.env +``` + +### 3. Configure (Optional) + +Edit `server/.env` to customize: + +```env +# Server port +PORT=3001 + +# ACE-Step API URL (default: http://localhost:8001) +ACESTEP_API_URL=http://localhost:8001 + +# Database location +DATABASE_PATH=./data/acestep.db + +# Optional: Pexels API key for video backgrounds +# Get a free key at https://www.pexels.com/api/ +PEXELS_API_KEY=your_key_here +``` + +## Usage + +### Step 1: Start ACE-Step API Server + +In a terminal, start the ACE-Step API server: + +```bash +cd /path/to/ACE-Step +uv run acestep-api --port 8001 +``` + +Wait until you see "Application startup complete" before proceeding. + +### Step 2: Start ACE-Step UI + +In another terminal: + +```bash +cd ace-step-ui +./start.sh +``` + +Or manually in two terminals: + +```bash +# Terminal 1 - Backend +cd server && npm run dev + +# Terminal 2 - Frontend +npm run dev +``` + +### Step 3: Open the UI + +Open http://localhost:3000 in your browser. + +On first launch, you'll be asked to set a username. This is stored locally. + +## Generating Music + +1. **Simple Mode**: Enter a description of the music you want +2. **Custom Mode**: Fine-tune parameters like BPM, key, duration, and add lyrics +3. Click "Create" to generate + +Generated songs are saved locally and appear in your library. + +## Additional Features + +### Audio Editor +Click the waveform icon on any song to open the built-in audio editor for trimming, fading, and effects. + +### Stem Extraction +Extract vocals, drums, bass, and other stems from any song using the Demucs-powered stem separator. + +### Video Generator +Create music videos with: +- Custom backgrounds from Pexels (requires API key) +- Gradient animations +- Lyrics display +- Album art overlay + +## Troubleshooting + +### "ACE-Step API not reachable" +Make sure the ACE-Step API server is running on port 8001: +```bash +cd /path/to/ACE-Step +uv run acestep-api --port 8001 +``` + +### "CUDA out of memory" +- Close other GPU-intensive applications +- Try generating shorter clips (30-60 seconds) +- Reduce batch size if available + +### Songs show 0:00 duration +This can happen if FFprobe is not installed. Install it: +```bash +# Ubuntu/Debian +sudo apt install ffmpeg + +# macOS +brew install ffmpeg +``` +New songs will automatically detect duration. For existing songs, they'll update when played. + +## Development + +```bash +# Run in development mode with hot reload +./start.sh + +# Build for production +npm run build +cd server && npm run build +``` + +## License + +MIT + +## Credits + +- [ACE-Step](https://github.com/ace-step/ACE-Step) - AI music generation model +- [Demucs](https://github.com/facebookresearch/demucs) - Audio source separation +- [Pexels](https://www.pexels.com) - Stock video backgrounds diff --git a/audiomass-editor/README.md b/audiomass-editor/README.md new file mode 100644 index 0000000..157a127 --- /dev/null +++ b/audiomass-editor/README.md @@ -0,0 +1,24 @@ +# AudioMass +Free full-featured web-based audio & waveform editing tool + + +Live: [https://audiomass.co](https://audiomass.co) + +--- + +## Getting it to Run! +1. please checkout this repo (or download it as zip) +2. navigate to it through your favorite CLI, then access the ```src``` dir +3. Run ```go run audiomass-server.go``` - or if you do not have golang installed, you can use a simple python webserver by running ```python audiomass-server.py``` +4. Navigate to [http://localhost:5055/](http://localhost:5055/) and have fun! + +... + + + +--- + +If you want to build the all.build.js minified file for delivery/publishing this then you can use uglify and run as: +```cat dist/wavesurfer.js dist/plugin/wavesurfer.regions.js oneup.js app.js keys.js contextmenu.js ui-fx.js ui.js modal.js state.js engine.js actions.js drag.js recorder.js welcome.js fx-pg-eq.js fx-auto.js local.js id3.js lzma.js | uglifyjs -c -m -o all.build.js``` + +Thanks! diff --git a/audiomass-editor/src/about.html b/audiomass-editor/src/about.html new file mode 100755 index 0000000..357438b --- /dev/null +++ b/audiomass-editor/src/about.html @@ -0,0 +1,321 @@ + + + + AudioMass - About + + + + + + + + + + + + + + + +
+ + +
+

Introducing AudioMass (https://audiomass.co) an open-source web based audio and waveform editing tool.

+ + + + + +

AudioMass lets you record, or use your existing audio tracks, and modify them by trimming, cutting, pasting or applying a plethora of effects, from compression and paragraphic equalizers to reverb, delay and distortion fx. AudioMass also supports more than 20 hotkeys combinations and a dynamic responsive interface to ensure ease of use and that your producivity remains high. +it is written solely in plain old-school javascript, weights approximately 65kb and has no backend or framework dependencies.

+ + +

It also has very good browser and device support.

+ + +
:: Feature List ::
+ +
    +
  • Loading Audio, navigating the waveform, zoom and pan
  • +
  • Visualization of frequency levels
  • +
  • Peak and distortion signaling
  • +
  • Cutting/Pasting/Trimming parts of the audio
  • +
  • Inverting and Reversing Audio
  • +
  • Exporting to mp3
  • +
  • Modifying volume levels
  • +
  • Fade In/Out
  • +
  • Compressor
  • +
  • Normalization
  • +
  • Reverb
  • +
  • Delay
  • +
  • Distortion
  • +
  • Pitch Shift
  • +
  • Keeps track of states so you can undo mistakes
  • +
  • Offline support!
  • +
+ +

And all this, in only 83kb of JS!

+
+ + +
+

Getting Started

+ + +

To get started, drag and drop an audio file, or try the included sample.
+Once the file is loaded and you can view the waveform, zoom in, pan around, or select a region.

+ + + + +

Recording Audio

+ +

To record audio, simply press the Recording button, or the [R] key.

+ + + + +

Exporting to mp3

+ +

In order to export back to mp3, click on 'File', then 'Export to mp3', and follow the modal's instructions.

+ + + +
+ + +
+ + +
+

The story behind AudioMass. And a short rant on web interfaces.

+ +

I wrote AudioMass back in June 2018 and it stayed dormant on my hard disk until I decided to share it with the world today (July 13th, 19 -- but you might be seeing this in 2020. Hi!!). +It started as a personal small tool for quick visualization of waveforms. Later I added the ability to cut/copy/paste as well as fade in and out. And soon after good 'ol feature creep and perfectionism took over! Soon after, it turned to a challenge to see how close to a full-featured waveform editor it can get, whilst maintaining acceptable performance and small filesize.

+ +

In general I am a big fan of the interfaces of DAWs (Digital Audio Workstations), they are extremely, complex, intricate, versatile, and they manage to remain visually pleasant even through their infinite options and knobs. Many times I feel the web has taken a very wrong turn, as amazing interfaces such as... + +

Sonar

+ + +
+

Fruity loops

+ + +
+ +

Existed for more than 10-15 years now, while we are struggling with animating some rectangles for 60fps... So for AudioMass I wanted to try and make a fast and performant interface. Drawing inspiration from the examples I mentioned earlier rather than the tradiional web development practices. This is my unconvincing but truthfull excuse as to why the code is ugly; it is focused on being fast and getting the job done, with little regard on structure.

+ +
+ +
+ +
+ +

Building the interface

+ +

Let's say we have a "PLAY" button and when we press it the track begins to play. I suppose we would want the button's color and state to reflect that the track is now playing. So naively we would do something like;

+ + +
btn.onclick = function () {
+	this.classList.add ('active');
+};
+ +

But what happens if we have a hotkey that triggers the same action? Let's say we press [SPACEBAR] and the track begins to play. Do we modify that button's class in the spacebar's handler?

+ +
document.onkeypress = function ( e ) { 
+  if ( e.keyCode === 32) {
+       e.preventDefault ();
+
+       document.querySelector ('.playbtn').classList.add ('active');
+  }
+};
+ +

And what happens, if there are 2 buttons, or one gets dynamically removed? Do we do selectAll and iterate? Hmmm...
+And if the track is playing and we hit [SPACEBAR] or the play button again, we need to stop playing. What do we do then? You can see how this becomes messy very quickly as everything gets very tighlty coupled together in a big dependency ball.

+ + + +

Introducing the observer pattern. Actions are represented by events. So the above logic and be expressed as;

+ + +
btn.onclick = function () {
+	FireEvent ('RequestTogglePlay');
+};
+
+On ('WillPlay', function () {
+	btn.classList.add ('active');
+});
+
+On ('WillStop', function () {
+	btn.classList.remove ('active');
+});
+
+
+
+document.onkeypress = function ( e ) {
+  if ( e.keyCode === 32) {
+       e.preventDefault ();
+
+       FireEvent ('RequestTogglePlay');
+  }
+};
+
+
+
+On ('RequestTogglePlay', function () {
+	if (track.is_playing) {
+		FireEvent ('WillStop');
+		track.stop ();
+	}
+	else {
+		FireEvent ('WillPlay');
+		track.play ();
+	}
+});
+
+track.onPlayStart = function () {
+	FireEvent ('DidPlay');
+};
+track.onPlayStop = function () {
+	FireEvent ('DidStop');
+};
+
+ +

Now this is completely decoupled and dependency free! The button will set its state according to the events it receives, and both the button and the spacebar key rely on the same mechanisms. +You may notice the vocabulary we are using. "Request", "Will" and "Did". These are arbitrarilly chosen to impose some extra structure.
"Request" denotes intent to perform an action, it is not guaranteed that the action will execute as there might be conditions preventing it (eg unitialized or still loading objects). "Will" means that the conditions passed and we are attempting to perform the action. And "Did" means that the action just got performed.
+It might be a bit too verbose, but it worked very well for structuring AudioMass's interface.

+
+ +
+ +
+

Dockable UI

+ +

One thing I love about DAW interfaces, is that every window can be pulled out of the main host. I fondly remember having 3 screens full of VST plugins. So can we do the same in the browser?

+ + + + + +

Yes! And it is using some of the oldest tricks in the book. Essentially we create a pop-up window with window.open and just pass buffers to its documentWindow object. Surprisingly it is quite performant on all browsers except IE Edge. I believe they are serializing in ascii or base64 every packet or something. Also Chrome has an interesting bug where you can't pass more than 512 byte buffers.

+ +

So for the undocked window, we call window.open. But how do we make it work when it is docked? It would be quite cumbersome to write the same functionality twice, once as a standalone page, and once as an in-page script. Luckily we can avoid that completely, and re-use the same page by using iframes.

+ +

The only difference is that the undocked version uses window.opener to refference its parent, whereas the iframe uses window.parent.

+ +
+ + +
+ +
+

Future work and performance considerations

+ +

The next big feature that is planned, is multitrack support. The ability to mix tracks and different sounds is currently lacking and its usefulness as it stands is limited.

+ +
+ +

There is also a lot of room for improvement in almost all aspects.

+ +

First of all we can further reduce the filesize by around 20kb by removing the library we are using for rendering the waveform. We use only a fraction of its functionality so there is no reason to include it all.

+ +

We can also optimize a lot the rendering of the waveform. I heavily modified the library used to compute and draw only the visible range. However it is still clearing and re-drawing all of the canvas at each frame. We can take advantage of 2d Context's translate calls, and shift the canvas around instead of redrawing all of the pixels.

+ +

We can also move some operations to a background thread, such as the filters processing so that the UI does not freeze when applying a long chain of effects.

+ +
+ + +

However, the biggest issue I encountered, is the Web Audio API itself. Every operation results in iterating over multiple long arrays per frame. Eventually the garbage collector fires and crackling is introduced. Only way to go around this is to use a small fftSize, but then the frequency range we have to work with is very narrow. Perhaps a pure WASM implementation would outperform trying to modify audio signals with JS. Only one way to find out I guess :)

+

Additionally, decodeAudioData provides no progress callback, and no way of cancelling it. So if you attempt to load a huge audio file, you will waste resources until it gets processed. There is no way around this currently and it can get annoying if you push a big file by mistake.

+ +
+ +


+ +
+ + + \ No newline at end of file diff --git a/audiomass-editor/src/about/audiomass_2.jpg b/audiomass-editor/src/about/audiomass_2.jpg new file mode 100755 index 0000000..36d34a7 Binary files /dev/null and b/audiomass-editor/src/about/audiomass_2.jpg differ diff --git a/audiomass-editor/src/about/audiomass_3.jpg b/audiomass-editor/src/about/audiomass_3.jpg new file mode 100755 index 0000000..07bc389 Binary files /dev/null and b/audiomass-editor/src/about/audiomass_3.jpg differ diff --git a/audiomass-editor/src/about/audiomass_4.jpg b/audiomass-editor/src/about/audiomass_4.jpg new file mode 100755 index 0000000..b7c1edf Binary files /dev/null and b/audiomass-editor/src/about/audiomass_4.jpg differ diff --git a/audiomass-editor/src/about/audiomass_support.jpg b/audiomass-editor/src/about/audiomass_support.jpg new file mode 100755 index 0000000..d6a2543 Binary files /dev/null and b/audiomass-editor/src/about/audiomass_support.jpg differ diff --git a/audiomass-editor/src/about/audiomass_top.jpg b/audiomass-editor/src/about/audiomass_top.jpg new file mode 100755 index 0000000..254c99d Binary files /dev/null and b/audiomass-editor/src/about/audiomass_top.jpg differ diff --git a/audiomass-editor/src/about/dock_ui.mp4 b/audiomass-editor/src/about/dock_ui.mp4 new file mode 100755 index 0000000..656c76e Binary files /dev/null and b/audiomass-editor/src/about/dock_ui.mp4 differ diff --git a/audiomass-editor/src/about/fruity.png b/audiomass-editor/src/about/fruity.png new file mode 100755 index 0000000..a5424dd Binary files /dev/null and b/audiomass-editor/src/about/fruity.png differ diff --git a/audiomass-editor/src/about/sonar.jpg b/audiomass-editor/src/about/sonar.jpg new file mode 100755 index 0000000..d0c45cf Binary files /dev/null and b/audiomass-editor/src/about/sonar.jpg differ diff --git a/audiomass-editor/src/actions.js b/audiomass-editor/src/actions.js new file mode 100755 index 0000000..07acbfe --- /dev/null +++ b/audiomass-editor/src/actions.js @@ -0,0 +1,1788 @@ +(function( PKAE ) { + 'use strict'; + + function AudioUtils ( master, wavesurfer ) { + + // audio destination + var audio_destination = wavesurfer.backend.analyser; + var audio_ctx = wavesurfer.backend.ac; + var audio_script_node = audio_ctx.createScriptProcessor(256); + + function loadDecoded ( new_buffer ) { + wavesurfer.loadDecodedBuffer ( new_buffer ); + master.fireEvent ('DidUpdateLen', wavesurfer.getDuration ()); + }; + + function OverwriteBufferWithSegment (_offset, _duration, withBuffer ) { + var originalBuffer = wavesurfer.backend.buffer; + TrimBuffer( _offset, _duration, true ); + var ret = InsertSegmentToBuffer ( _offset, withBuffer ); + + setTimeout (function() { + wavesurfer.drawBuffer(); + },40); + + return (ret); + } + + function OverwriteBuffer ( withBuffer ) { + loadDecoded ( withBuffer ); + setTimeout (function() { + wavesurfer.drawBuffer(); + },40); + } + + function MakeSilenceBuffer ( _duration ) { + var originalBuffer = wavesurfer.backend.buffer; + var emptySegment = wavesurfer.backend.ac.createBuffer( + originalBuffer.numberOfChannels, + _duration * originalBuffer.sampleRate, + originalBuffer.sampleRate + ); + + return (emptySegment); + } + + + function CopyBufferSegment( _offset, _duration ) { + var originalBuffer = wavesurfer.backend.buffer; + + var new_len = ((_duration/1) * originalBuffer.sampleRate) >> 0; + var new_offset = ((_offset/1) * originalBuffer.sampleRate) >> 0; + + var emptySegment = wavesurfer.backend.ac.createBuffer ( + wavesurfer.SelectedChannelsLen, + new_len, + originalBuffer.sampleRate + ); + + for (var i = 0, u = 0; i < wavesurfer.ActiveChannels.length; ++i) { + if (wavesurfer.ActiveChannels[ i ] === 0) continue; + + emptySegment.getChannelData ( u ).set ( + originalBuffer.getChannelData ( i ).slice ( new_offset, new_len + new_offset ) + ); + + ++u; + } + return (emptySegment); + }; + + + function TrimBuffer( _offset, _duration, force ) { + var originalBuffer = wavesurfer.backend.buffer; + + var new_len = ((_duration/1) * originalBuffer.sampleRate) >> 0; + var new_offset = ((_offset/1) * originalBuffer.sampleRate) >> 0; + + var emptySegment = wavesurfer.backend.ac.createBuffer ( + !force ? wavesurfer.SelectedChannelsLen : originalBuffer.numberOfChannels, + new_len, + originalBuffer.sampleRate + ); + + var uberSegment = null; + + if (!force && wavesurfer.SelectedChannelsLen < originalBuffer.numberOfChannels) + { + uberSegment = wavesurfer.backend.ac.createBuffer ( + originalBuffer.numberOfChannels, + originalBuffer.length, + originalBuffer.sampleRate + ); + + for (var i = 0; i < originalBuffer.numberOfChannels; ++i) { + var chan_data = originalBuffer.getChannelData ( i ); + var uber_chan_data = uberSegment.getChannelData ( i ); + + if (wavesurfer.ActiveChannels[ i ] === 0) + { + uber_chan_data.set ( + chan_data + ); + } + else + { + var segment_chan_data = emptySegment.getChannelData (0); + + segment_chan_data.set ( + chan_data.slice ( new_offset, new_offset + new_len ) + ); + + uber_chan_data.set ( + chan_data.slice ( 0, new_offset ) + ); + + uber_chan_data.set ( + chan_data.slice ( new_offset + new_len ), new_offset + new_len + ); + } + } + } + else + { + uberSegment = wavesurfer.backend.ac.createBuffer( + originalBuffer.numberOfChannels, + originalBuffer.length - new_len, + originalBuffer.sampleRate + ); + + for (var i = 0; i < originalBuffer.numberOfChannels; ++i) { + var chan_data = originalBuffer.getChannelData(i); + var segment_chan_data = emptySegment.getChannelData(i); + var uber_chan_data = uberSegment.getChannelData(i); + + segment_chan_data.set ( + chan_data.slice ( new_offset, new_offset + new_len ) + ); + + uber_chan_data.set ( + chan_data.slice ( 0, new_offset ) + ); + + uber_chan_data.set ( + chan_data.slice ( new_offset + new_len ), new_offset + ); + } + } + + loadDecoded ( uberSegment, originalBuffer ); + + return (emptySegment); + }; + + + + function InsertSegmentToBuffer( _offset, buffer ) { + var originalBuffer = wavesurfer.backend.buffer; + var uberSegment = wavesurfer.backend.ac.createBuffer( + originalBuffer.numberOfChannels, + originalBuffer.length + buffer.length, + originalBuffer.sampleRate + ); + + _offset = ((_offset / 1) * originalBuffer.sampleRate) >> 0; + + for (var i = 0; i < originalBuffer.numberOfChannels; ++i) { + + var chan_data = originalBuffer.getChannelData( i ); + var uberChanData = uberSegment.getChannelData( i ); + var segment_chan_data = null; + + if (buffer.numberOfChannels === 1) + segment_chan_data = buffer.getChannelData( 0 ); + else + segment_chan_data = buffer.getChannelData( i ); + + // check to see if we have only 1 channel selected + if (wavesurfer.SelectedChannelsLen === 1) + { + // check if we have the selected channel + if (wavesurfer.ActiveChannels[ i ] === 0) + { + // keep original + uberChanData.set ( + chan_data + ); + + continue; + } + } + + if (_offset > 0) + { + uberChanData.set ( + chan_data.slice ( 0, _offset ) + ); + } + + uberChanData.set ( + segment_chan_data, _offset + ); + + if (_offset < (originalBuffer.length + buffer.length) ) + { + uberChanData.set ( + chan_data.slice( _offset ), _offset + segment_chan_data.length + ); + } + } + + loadDecoded ( uberSegment, originalBuffer ); + + return [ + (_offset / originalBuffer.sampleRate), + (_offset / originalBuffer.sampleRate) + (buffer.length / originalBuffer.sampleRate) + ]; + }; + + + function ReplaceFloatArrays ( _offset, arrays ) { + var originalBuffer = wavesurfer.backend.buffer; + var arr_len = arrays.length; + var arr_samples = arrays[0].length; + + var new_len = (arr_samples * arr_len); + var buff_len = originalBuffer.length; + + _offset = ((_offset / 1) * originalBuffer.sampleRate) >> 0; + + if (buff_len < (_offset + new_len)) { + buff_len = (_offset + new_len); + } + + var uberSegment = wavesurfer.backend.ac.createBuffer ( + originalBuffer.numberOfChannels, + buff_len, + originalBuffer.sampleRate + ); + + for (var i = 0; i < originalBuffer.numberOfChannels; i++) { + var chan_data = originalBuffer.getChannelData( i ); + var uberChanData = uberSegment.getChannelData( i ); + + + if (_offset > 0) + { + uberChanData.set ( + chan_data.slice ( 0, _offset ) + ); + } + + for (var j = 0; j < arr_len; ++j) + { + uberChanData.set ( + arrays[ j ], _offset + (j * arr_samples) + ); + } + + if (_offset < (originalBuffer.length + new_len) ) + { + uberChanData.set ( + chan_data.slice( _offset + new_len ), _offset + new_len + ); + } + } + + loadDecoded ( uberSegment, originalBuffer ); + + return [ + (_offset / originalBuffer.sampleRate), + (_offset / originalBuffer.sampleRate) + (new_len / originalBuffer.sampleRate) + ]; + }; + + function InsertFloatArrays( _offset, arrays ) { + var originalBuffer = wavesurfer.backend.buffer; + var arr_len = arrays.length; + var arr_samples = arrays[0].length; + + var new_len = (arr_samples * arr_len); + + _offset = ((_offset / 1) * originalBuffer.sampleRate) >> 0; + + var uberSegment = wavesurfer.backend.ac.createBuffer( + originalBuffer.numberOfChannels, + originalBuffer.length + new_len, + originalBuffer.sampleRate + ); + + for (var i = 0; i < originalBuffer.numberOfChannels; i++) { + var chan_data = originalBuffer.getChannelData( i ); + var uberChanData = uberSegment.getChannelData( i ); + + + if (_offset > 0) + { + uberChanData.set ( + chan_data.slice ( 0, _offset ) + ); + } + + for (var j = 0; j < arr_len; ++j) + { + uberChanData.set ( + arrays[ j ], _offset + (j * arr_samples) + ); + } + + if (_offset < (originalBuffer.length + new_len) ) + { + uberChanData.set ( + chan_data.slice( _offset ), _offset + new_len + ); + } + } + + loadDecoded ( uberSegment, originalBuffer ); + + return [ + (_offset / originalBuffer.sampleRate), + (_offset / originalBuffer.sampleRate) + (new_len / originalBuffer.sampleRate) + ]; + }; + + function getAudioContext() { + if (!window.WaveSurferAudioContext) { + window.WaveSurferAudioContext = new (window.AudioContext || + window.webkitAudioContext)(); + } + return window.WaveSurferAudioContext; + } + function getOfflineAudioContext (channels, sampleRate, duration) { + return new (window.OfflineAudioContext || + window.webkitOfflineAudioContext)(channels, duration, sampleRate); + }; + + function initPreview (val) { + this.previewVal = val; + }; + + function stopPreview (_fx) { + if (!this.previewing) return ; + + if (_fx) { + _fx.destroy && _fx.destroy (); + } + + if (this.PreviewFilter) + { + if (this.PreviewFilter.length > 0) + { + for (var ii = 0; ii < this.PreviewFilter.length; ++ii) + this.PreviewFilter[ ii ].disconnect (); + } + else + this.PreviewFilter.disconnect (); + } + + var script_node = audio_script_node; // wavesurfer.backend.scriptNode + + script_node.disconnect (); + wavesurfer.backend.scriptNode.connect (audio_ctx.destination); + // wavesurfer.backend.scriptNode.connect (audio_ctx.destination); + // wavesurfer.backend.scriptNode.onaudioprocess = null; + + this.PreviewSource.stop(); + this.PreviewSource.disconnect (); + + this.PreviewDestination = this.PreviewSource = this.PreviewFilter = this.PreviewUpdate = null; + this.previewing = 0; + } + function togglePreview () { + if (!this.previewing) { + + this.previewVal = !this.previewVal; + return (this.previewVal); + } + + if (this.previewing === 2) + { +// if (this.PreviewFilter) +// { +// if (this.PreviewFilter.length > 0) +// { +// for (var ii = 0; ii < this.PreviewFilter.length; ++ii) +// this.PreviewFilter[ ii ].disconnect (); +// } +// else +// this.PreviewFilter.disconnect (); +// } + + if (this.PreviewTog) { + this.PreviewTog (false, this.PreviewSource); + } + + this.PreviewSource.disconnect (); + this.PreviewSource.connect (this.PreviewDestination); + this.previewing = 1; + this.previewVal = false; + + return (false); + } + else + { + this.PreviewSource.disconnect (); + + if (this.PreviewFilter) + { + if (this.PreviewFilter.length > 0) + { + !this.PreviewFilter[ 0 ].buffer && this.PreviewSource.connect (this.PreviewFilter[ 0 ]); +// var ii = 0; +// for (; ii < this.PreviewFilter.length - 1; ++ii) +// { +// this.PreviewFilter[ ii ].disconnect (); +// this.PreviewFilter[ ii ].connect (this.PreviewFilter[ ii + 1 ]); +// } +// this.PreviewFilter[ ii ].connect (this.PreviewDestination); + } + else + { + !this.PreviewFilter.buffer && this.PreviewSource.connect (this.PreviewFilter); + this.PreviewFilter.disconnect (); + this.PreviewFilter.connect (this.PreviewDestination); + } + } + + if (this.PreviewTog) { + this.PreviewTog (true, this.PreviewSource); + } + + this.previewing = 2; + this.previewVal = true; + + return (true); + } + } + + + function previewEffect ( _offset, _duration, _fx ) { + if (this.previewing) stopPreview (_fx); + + var orig_buffer = wavesurfer.backend.buffer; + + if (!_offset && !_duration) + { + _offset = 0; + _duration = (orig_buffer.length / orig_buffer.sampleRate) >> 0; + } + + var script_node = audio_script_node; //wavesurfer.backend.scriptNode; + var fx_buffer = CopyBufferSegment (_offset, _duration); + var audio_ctx = wavesurfer.backend.ac || getAudioContext (); + var source = audio_ctx.createBufferSource (); + source.buffer = fx_buffer; + source.loop = true; + + this.PreviewFilter = this.PreviewTog = null; + if (!_fx) + source.connect (audio_destination); + else + { + this.PreviewTog = _fx.preview; + this.PreviewUpdate = _fx.update; + this.PreviewFilter = _fx.filter ( audio_ctx, audio_destination, source, _duration/1 ); + } + + script_node.disconnect (); + wavesurfer.backend.scriptNode.disconnect (); + script_node.connect( audio_ctx.destination ); + + var skipp = 1; + var prev_fft = 0; + var dataArray = null; + + script_node.onaudioprocess = ( e ) => { + + var loudness = [0, 0]; + var temp = 0; + // var flip = false; + --skipp; + + if (skipp === 0) + { + if (audio_destination.getFloatTimeDomainData) + { + if (prev_fft !== audio_destination.fftSize) + { + dataArray = new Float32Array(audio_destination.fftSize); // Float32Array needs to be the same length as the fftSize + prev_fft = audio_destination.fftSize; + } + audio_destination.getFloatTimeDomainData (dataArray); // fill the Float32Array with data returned from getFloatTimeDomainData() + + for (var j = 0; j < audio_destination.fftSize; j += 1) { + var x = dataArray[j]; + if (Math.abs(x) >= temp) { + temp = Math.abs(x); + } + } + + loudness[0] = 20 * Math.log10(temp) + 0.001; + } + else + { + if (prev_fft !== audio_destination.fftSize) + { + dataArray = new Uint8Array(audio_destination.fftSize); // Float32Array needs to be the same length as the fftSize + prev_fft = audio_destination.fftSize; + } + audio_destination.getByteTimeDomainData (dataArray); // fill the Float32Array with data returned from getFloatTimeDomainData() + + var total_float = 0; + + for (var j = 0; j < audio_destination.fftSize; j += 1) { + var float = ( dataArray[j] / 0x80 ) - 1; + total_float += ( float * float ); + } + var rms = Math.sqrt (total_float / audio_destination.fftSize); + loudness[0] = 20 * ( Math.log(rms) / Math.log(10) ); + } + + if (loudness[0] < -100) loudness[0] = -100; + loudness[1] = loudness[0]; + + // audio_destination.fftSize = 512; + audio_destination.getByteFrequencyData( wavesurfer.backend.FreqArr ); + + //wavesurfer.backend.peak_frequency = Math.max.apply( null, wavesurfer.backend.FreqArr ); + master.fireEvent ('DidAudioProcess',[-1, loudness, e.timeStamp], wavesurfer.backend.FreqArr); + // wavesurfer.backend.peak_frequency = [0, 0]; + skipp = 2; + } + }; + + source.start (); + + this.PreviewSource = source; + this.PreviewDestination = audio_destination; + this.previewing = 2; + + if (!this.previewVal) + { + togglePreview.call (this); + } + + return (source); + } + + function applyEffect( _offset, _duration, _fx ) { + var orig_buffer = wavesurfer.backend.buffer; + + if (!_offset && !_duration) + { + _offset = 0; + _duration = (orig_buffer.length / orig_buffer.sampleRate) >> 0; + } + + if (_offset <0) _offset = 0; + if (wavesurfer.getDuration () < _duration) + _duration = wavesurfer.getDuration (); + + var fx_buffer = CopyBufferSegment ( _offset, _duration ); + var new_offset = ((_offset/1) * orig_buffer.sampleRate) >> 0; + + var audio_ctx = getOfflineAudioContext ( + wavesurfer.SelectedChannelsLen, // orig_buffer.numberOfChannels, + orig_buffer.sampleRate, + fx_buffer.length + ); + + var source = audio_ctx.createBufferSource (); + source.buffer = fx_buffer; + + var filter = null; + if (_fx) { + filter = _fx.filter ( audio_ctx, audio_ctx.destination, source, _duration/1 ); + filter.destroy && filter.destroy (); + } + + source.start (); + + var offline_callback = function( rendered_buffer ) { + var uber_buffer = wavesurfer.backend.ac.createBuffer( + orig_buffer.numberOfChannels, + orig_buffer.length, + orig_buffer.sampleRate + ); + + for (var i = 0; i < orig_buffer.numberOfChannels; ++i) + { + var uber_chan_data = uber_buffer.getChannelData (i); + var chan_data = orig_buffer.getChannelData (i); + + // check if channel is active + if (wavesurfer.ActiveChannels[ i ] === 0) + { + uber_chan_data.set ( + chan_data + ); + continue; + } + + var fx_chan_data = null; + if (rendered_buffer.numberOfChannels === 1) + fx_chan_data = rendered_buffer.getChannelData( 0 ); + else + fx_chan_data = rendered_buffer.getChannelData( i ); + + uber_chan_data.set ( + chan_data + ); + + uber_chan_data.set ( + fx_chan_data, new_offset, fx_chan_data.length - new_offset + ); + } + + loadDecoded ( uber_buffer ); + + if (filter.length > 0) { + for (var i = 0; i < filter.length; ++i) filter[i].disconnect (); + } else filter && filter.disconnect && filter.disconnect (); + + // is this needed? + rendered_buffer = fx_buffer = filter = null; + source.disconnect (); + // audio_ctx.close (); + // - + }; + + var offline_renderer = audio_ctx.startRendering(); + if (offline_renderer) + offline_renderer.then( offline_callback ).catch(function(err) { + console.log('Rendering failed: ' + err); + }); + else + audio_ctx.oncomplete = function ( e ) { + offline_callback ( e.renderedBuffer ); + }; + }; + + +/* + /////////////// ----------------------- + // ATTEMPTING BACKGROUND NOISE REMOVAL + function findTopFrequencies (_offset, _duration, callback) { + var q = this; + + var audio_ctx = getAudioContext (); + var buffer_source = audio_ctx.createBufferSource(); + buffer_source.buffer = CopyBufferSegment (_offset, _duration); + + var analyser = audio_ctx.createAnalyser (); + analyser.fftSize = 2048; + analyser.minDecibelsis = -40; + analyser.maxDecibelsis = 0; + var scp = audio_ctx.createScriptProcessor (256, 0, 1); + + buffer_source.connect (analyser); + scp.connect (audio_ctx.destination); + // buffer_source.loop = true; + + var samples = 0; + var finger_print = new Uint16Array (analyser.frequencyBinCount); + var freq_data = new Uint8Array (analyser.frequencyBinCount); + scp.onaudioprocess = function () { + analyser.getByteFrequencyData (freq_data); + + for (var i = 0; i < freq_data.length; ++i) + { + finger_print[ i ] += freq_data [ i ]; + } + ++samples; + }; + buffer_source.onended = function() { + + var sampleRate = buffer_source.buffer.sampleRate; + buffer_source.stop (); + buffer_source.disconnect (); + scp.disconnect (); + + for (var i = 0; i < finger_print.length; ++i) + { + finger_print[ i ] /= samples >> 0; + if (finger_print[ i ] < 10) { + finger_print[ i ] = 0; + } + } + + callback && callback.apply (q, [finger_print] ); + }; + buffer_source.start (0); + } + function killdTopFrequencies (_offset, _duration, _noise_profile) { + var q = this; + var step = function ( _offset, _duration, callback ) { + findTopFrequencies (_offset, _duration, function( frequencies ) { + var similarity = []; + var similar_frequencies = 0; + + for (var i = 0; i < _noise_profile.length; ++i) + { + var val = Math.abs ( frequencies[ i ] - _noise_profile[ i ] ); + if (val < 10) + { + similarity[ i ] = (val == 0 && _noise_profile[ i ] > 0) ? 5 : val; + ++similar_frequencies; + } + } + + if ( similar_frequencies > _noise_profile.length / 3) + { + cleanUpSpecificAudioRange.apply (q, [_offset, _duration, similarity]); + } + + callback && callback (); + }); + }; + if (_duration <= 0.1) step ( _offset, _duration ); + else + { + var new_offset = _offset; + var goal = _offset + _duration; + + var test = function () { + if ( new_offset < goal ) { + var dur_step = 0.1; + if (new_offset + dur_step > goal) dur_step = goal - new_offset; + + step ( new_offset, dur_step, test ); + new_offset += dur_step; + } + } + test (); + // - + + } + } + function cleanUpSpecificAudioRange (_offset, _duration, _frequencies) { + // var fx_buffer = CopyBufferSegment (_offset, _duration); + var val = []; + var all_ok = false; + + for (var i = 0; i < _frequencies.length; ++i) + { + if (!_frequencies[i]) continue; + val.push({ + 'type' : 'notch', + 'freq' : (i * wavesurfer.backend.ac.sampleRate/_frequencies.length)/2, + 'val' : -35,//(_frequencies[i]), + 'q' : 10.0 + }); + all_ok = true; + } + + if (all_ok) + { + var ff = this.FXBank.ParametricEQ( val ); + this.FX( _offset, _duration, ff ); + } + +*/ + +/* + var bands = []; + var len = val.length; + + var makeEQ = function ( band ) { + var eq = audio_ctx.createBiquadFilter (); + eq.type = band.type; + eq.gain.value = ~~band.val; + eq.Q.value = 1; + eq.frequency.value = band.freq; + + return (eq); + }; + + var eq = makeEQ ( val [0] ); + bands.push ( eq ); + source.connect (eq); + + for (var i = 1; i < len - 1; ++i) + { + eq = makeEQ ( val [ i ] ); + bands [ i - 1 ].connect ( eq ); + bands.push ( eq ); + } + eq = makeEQ ( val [ len - 1 ] ); + bands [ bands.length - 1 ].connect ( eq ); + bands.push ( eq ); + eq.connect (audio_ctx.destination); + + return (bands); +*/ +// } + // ENDOF ATTEMPTING BACKGROUND NOISE REMOVAL + /////////////// ----------------------- + + + var worker = null; + function DownloadFileCancel () { + if (worker) { + worker.terminate (); + worker = null; + } + } + + function DownloadFile( with_name, format, kbps, selection, stereo, callback ) { + if (wavesurfer && wavesurfer.backend && wavesurfer.backend.buffer){} + else { + return false; + } + + + if (format === 'mp3') { + worker = new Worker('lame.js'); + } + else if (format === 'flac') { + worker = new Worker('flac.js'); + } + else { + worker = new Worker('wav.js'); + } + + var originalBuffer = wavesurfer.backend.buffer; + var sample_rate = originalBuffer.sampleRate; + + var channels = originalBuffer.numberOfChannels; + + var data_left = originalBuffer.getChannelData ( 0 ); + var data_right = null; + if (channels === 2) + data_right = originalBuffer.getChannelData ( 1 ); + + if (!stereo && channels === 2) + { + if (!wavesurfer.ActiveChannels[0] && wavesurfer.ActiveChannels[1]) + { + data_left = originalBuffer.getChannelData ( 1 ); + data_right = null; + channels = 1; + } + } + + if (stereo && !data_right) + { + data_right = data_left; + channels = 2; + } + else if (!stereo && data_right) + { + data_right = null; + channels = 1; + } + + var len = data_left.length, i = 0; + var offset = 0; + + if (selection) + { + offset = (selection[0] * sample_rate) >> 0; + len = ((selection[1] * sample_rate) >> 0) - offset; + } + + var dataAsInt16ArrayLeft = new Int16Array(len); + var dataAsInt16ArrayRight = null; + + + if (data_right) + { + dataAsInt16ArrayRight = new Int16Array(len); + + while(i < len) { + dataAsInt16ArrayLeft[i] = convert(data_left[offset + i]); + dataAsInt16ArrayRight[i] = convert(data_right[offset + i]); + ++i; + } + } + else + { + while(i < len) { + dataAsInt16ArrayLeft[i] = convert(data_left[offset + i]); + ++i; + } + } + function convert ( n ) { + var v = n < 0 ? n * 32768 : n * 32767; // convert in range [-32768, 32767] + return Math.max(-32768, Math.min(32768, v)); // clamp + } + + worker.onmessage = function( ev ) { + if (ev.data.percentage) + { + callback && callback ( ev.data.percentage ); + return ; + } + forceDownload( ev.data ); + + worker.terminate (); + worker = null; + } + + worker.postMessage ({ + sample_rate: sample_rate, + kbps:!kbps ? 128 : kbps, + flac_compression: kbps, + channels: channels + }); + worker.postMessage ( dataAsInt16ArrayLeft.buffer, [dataAsInt16ArrayLeft.buffer] ); + if (data_right) + worker.postMessage ( dataAsInt16ArrayRight.buffer, [dataAsInt16ArrayRight.buffer] ); + else + worker.postMessage (null); + + // function forceDownload ( mp3Data ) { + // var blob = new Blob (mp3Data, {type:'audio/mp3'}); + function forceDownload ( blob ) { + var url = (window.URL || window.webkitURL).createObjectURL(blob); + + var a = document.createElement( 'a' ); + a.href = url; + a.download = with_name ? with_name : 'output.mp3'; + a.style.display = 'none'; + document.body.appendChild( a ); + a.click(); + + callback && callback ('done'); + } + } + + function updatePreview ( val ) { + if (!this.previewing) return ; + this.PreviewUpdate && this.PreviewUpdate ( this.PreviewFilter, audio_ctx, val, this.PreviewSource ); + } + + + // EFFECTS LOGIC + var FXBank = { + Gain : function( val ) { + return { + filter : function ( audio_ctx, destination, source, duration ) { + var gain = audio_ctx.createGain (); + + for (var k = 0; k < val.length; ++k) + { + var curr = val[k]; + if (curr.length) + { + for (var i = 0; i < curr.length; ++i) { + gain.gain.linearRampToValueAtTime (curr[i].val, audio_ctx.currentTime + curr[i].time); + } + } + else + { + gain.gain.setValueAtTime ( curr.val, audio_ctx.currentTime ); + } + } + + gain.connect (destination); + source.connect (gain); + + return (gain); + }, + update : function ( gain, audio_ctx, val ) { + for (var k = 0; k < val.length; ++k) + { + var curr = val[k]; + if (curr.length) + { + for (var i = 0; i < curr.length; ++i) { + gain.gain.linearRampToValueAtTime (curr[i].val, audio_ctx.currentTime + curr[i].time); + } + } + else + { + gain.gain.setValueAtTime ( curr.val, audio_ctx.currentTime ); + } + } + // ---- + } + }; + }, + + FadeIn : function( val ) { + return { + filter : function ( audio_ctx, destination, source, duration ) { + var gain = audio_ctx.createGain (); + gain.gain.setValueAtTime (0, audio_ctx.currentTime); + gain.gain.linearRampToValueAtTime (1, audio_ctx.currentTime + duration/1); + gain.connect (destination); + source.connect (gain); + + return (gain); + } + }; + }, + + FadeOut : function( val ) { + return { + filter : function ( audio_ctx, destination, source, duration ) { + var gain = audio_ctx.createGain (); + gain.gain.setValueAtTime (1, audio_ctx.currentTime); + gain.gain.linearRampToValueAtTime (0, audio_ctx.currentTime + duration/1); + gain.connect (destination); + source.connect (gain); + + return (gain); + } + }; + }, + + Compressor : function ( val ) { + return { + filter : function ( audio_ctx, destination, source, duration ) { + var compressor = audio_ctx.createDynamicsCompressor (); + + for (var k in val) + { + if (val[k].length) + { + for (var i = 0; i < val[k].length; ++i) + { + var curr = val[k][i]; + compressor[k].linearRampToValueAtTime (curr.val, audio_ctx.currentTime + curr.time); + } + } + else + { + compressor[k].setValueAtTime ( val[k].val, audio_ctx.currentTime ); + } + } + + compressor.connect (destination); + source.connect (compressor); + + return (compressor); + }, + update : function ( compressor, audio_ctx, val ) { + for (var k in val) + { + if (val[k].length) + { + for (var i = 0; i < val[k].length; ++i) + { + var curr = val[k][i]; + compressor[k].linearRampToValueAtTime (curr.val, audio_ctx.currentTime + curr.time); + } + } + else + { + compressor[k].setValueAtTime ( val[k].val, audio_ctx.currentTime ); + } + } + // --- + } + }; + }, + + Reverse : function ( val ) { + return { + filter : function ( audio_ctx, destination, source, duration ) { + + for (var i = 0; i < source.buffer.numberOfChannels; ++i) { + Array.prototype.reverse.call( source.buffer.getChannelData (i) ); + } + + source.connect (destination); + return (source); + }, + update : function () {} + }; + }, + + Invert : function ( val ) { + return { + filter : function ( audio_ctx, destination, source, duration ) { + + for (var i = 0; i < source.buffer.numberOfChannels; ++i) { + var channel = source.buffer.getChannelData (i); + + for (var j = 0; j < channel.length; ++j) + channel[j] *= -1; + } + + source.connect (destination); + return (source); + }, + update : function () {} + }; + }, + + Flip : function ( val, val2 ) { + return { + filter : function ( audio_ctx, destination, source, duration ) { + + if (val === 'flip') + { + var chan0 = source.buffer.getChannelData (0); + var chan1 = source.buffer.getChannelData (1); + var tmp = 0; + + for (var j = 0; j < chan0.length; ++j) + { + tmp = chan0[j]; + chan0[j] = chan1[j]; + chan1[j] = tmp; + } + } + + source.connect (destination); + return (source); + }, + update : function () {} + }; + }, + + Normalize : function ( val ) { //todo ASM JS?? + return { + filter : function ( audio_ctx, destination, source, duration ) { + var max_val = val[1] || 1.0; + var equally = val[0]; + var max_peak = 0; + + for (var i = 0; i < source.buffer.numberOfChannels; ++i) { + var chan_data = source.buffer.getChannelData (i); + + // iterating faster first time... + for (var k = 1, len = chan_data.length; k < len; k = k + 10) { + var curr = Math.abs ( chan_data [ k ] ); + if (max_peak < curr) + max_peak = curr; + } + + var diff = max_val / max_peak; + + if (!equally) { + for (var k = 0, len = chan_data.length; k < len; ++k) { + chan_data[ k ] *= diff; + } + max_peak = 0; + } + } + + if (equally) { + var diff = max_val / max_peak; + + for (var i = 0; i < source.buffer.numberOfChannels; ++i) { + var chan_data = source.buffer.getChannelData (i); + + for (var k = 0, len = chan_data.length; k < len; ++k) { + chan_data[ k ] *= diff; + } + } + } + + source.connect (destination); + return (source); + }, + update : function () {} + }; + }, + + HardLimit : function ( val ) { //todo ASM JS?? + return { + filter : function ( audio_ctx, destination, source, duration ) { + var max_val = val[1] || 1.0; + var ratio = val[2] || 0.0; + var look_ahead = val[3] || 15; // ms + var equally = false; //val[0]; + var max_peak = 0; + + var buffer = audio_ctx.createBuffer( + source.buffer.numberOfChannels, + source.buffer.length, + source.buffer.sampleRate + ); + + look_ahead = (look_ahead * buffer.sampleRate/1000) >> 0; + + for (var i = 0; i < buffer.numberOfChannels; ++i) { + var chan_data = buffer.getChannelData (i); + chan_data.set ( source.buffer.getChannelData (i) ); + + // iterating faster first time... + for (var b = 0, len = chan_data.length; b < len; ++b) + { + for (var k = 0; k < look_ahead; k = k + 10) { + var curr = Math.abs ( chan_data [ b + k ] ); + if (max_peak < curr) + max_peak = curr; + } + + var diff = (max_val / max_peak); + + if (!equally) { + for (var k = 0; k < look_ahead; ++k) { + var orig_val = chan_data[ b + k ]; + var new_val = orig_val * diff; + + var peak_diff = max_val - Math.abs (new_val); + peak_diff *= orig_val < 0 ? -ratio : ratio; + + chan_data[ b + k ] = (new_val + peak_diff); + } + b += look_ahead; + max_peak = 0; + } + } + // ----- + } + + // todo handle disconnected LEFT AND RIGHT + var temp_source = audio_ctx.createBufferSource (); + temp_source.buffer = buffer; + temp_source.loop = true; + temp_source.start (); + + temp_source.connect (destination); + return (temp_source); + }, + update : function ( filtered_source, audio_ctx, val, source ) { + // stop the existing onerror + filtered_source.disconnect (); + filtered_source.buffer = null; + filtered_source = null; + + var ff = this.FXBank.HardLimit( val ); + this.PreviewFilter = ff.filter ( audio_ctx, audio_destination, source, 0 ); + } + }; + }, + + ParametricEQ : function ( val ) { + return { + filter : function ( audio_ctx, destination, source, duration ) { + + var bands = []; + var len = val.length; + + var makeEQ = function ( band ) { + var eq = audio_ctx.createBiquadFilter (); + + if (band.length) + { + for (var i = 0; i < band.length; ++i) + { + eq.gain.linearRampToValueAtTime (~~band[i].val, audio_ctx.currentTime + band[i].time); + } + + band = band[0]; + } + else eq.gain.value = ~~band.val; + + eq.type = band.type; + eq.Q.value = band.q || 1.0; + eq.frequency.value = band.freq; + + return (eq); + }; + + if (!val[0]) + { + val[0] = { + type:'peaking', + val:0, + q:1, + freq:500 + }; + } + + var eq = makeEQ ( val[0] ); + bands.push ( eq ); + source.connect (eq); + + if (val.length === 1) + { + eq.connect (destination); + return (bands); + } + + for (var i = 1; i < len - 1; ++i) + { + eq = makeEQ ( val [ i ] ); + bands [ i - 1 ].connect ( eq ); + bands.push ( eq ); + } + eq = makeEQ ( val[ len - 1 ] ); + bands [ bands.length - 1 ].connect ( eq ); + bands.push ( eq ); + eq.connect (destination); + + return (bands); + }, + update : function ( bands, audio_ctx, val, source ) { + + if (bands.length !== val.length) + { + var makeEQ = function ( band ) { + var eq = audio_ctx.createBiquadFilter (); + return (eq); + }; + + if (bands.length < val.length) + { + var l = val.length - bands.length; + while (l-- > 0) + { + var eq = makeEQ (); + var connect_to = bands[0]; + bands.unshift (eq); + eq.connect (connect_to); + } + + source.disconnect (); + source.connect (bands[0]); + } + else + { + if (val.length > 0) + { + var l = bands.length - val.length; + source.disconnect (); + + for (var i = 0; i < l; ++i) + { + var eq = bands.shift(); + eq.disconnect (); + } + + source.connect (bands[0]); + } + else + { + val[0] = { + type:'peaking', + val:0, + q:1, + freq:500 + }; + } + } + } + + var len = val.length; + for (var i = 0; i < len; ++i) + { + var eq = bands [ i ]; + eq.type = val[ i ].type; + eq.gain.value = ~~val[ i ].val; + eq.Q.value = val[ i ].q || 1.0; + eq.frequency.value = val[ i ].freq; + } + // - + } + }; + }, + + Rate : function ( val ) { + var prev_val = 1.0; + var temp_source = []; + + return { + filter : function ( audio_ctx, destination, source, duration ) { + var fx_buffer = source.buffer; + + var stretch_ratio = val; + let grainDuration = 0.05; // 50 ms grain + const analysisHop = 0.025; // 25 ms step (50% overlap) + const desiredOverlap = 0.5; // 50% overlap + const synthesisHop = analysisHop * stretch_ratio; // output hop + + if (stretch_ratio > 1) { + grainDuration = synthesisHop / (1 - desiredOverlap); // 0.15 sec (150 ms + } + + var offlineCtx = audio_ctx; + const now = audio_ctx.currentTime; + + // var filter = fx.filter ( offlineCtx, offlineCtx.destination, null, duration ); + var applyHannWindowFast = function (gainNode, outputTime, grainDuration) { + // The automation curve using a Hann window shape + const numSteps = 50; + + for (let i = 0; i <= numSteps; i++) { + const t = (i / numSteps) * grainDuration; + const windowValue = 0.5 * (1 - Math.cos((2 * Math.PI * t) / grainDuration)); + gainNode.gain.linearRampToValueAtTime(windowValue, outputTime + t); + } + }; + + // Schedule grains + var grainIndex = 0; + var filter_chain = []; + + for (let t = 0; t < fx_buffer.duration; t += analysisHop) { + const offset = t; + const outputTime = grainIndex * synthesisHop; + if (offset + grainDuration > fx_buffer.duration) break; // stop if beyond source + + const grainSource = offlineCtx.createBufferSource(); + grainSource.buffer = fx_buffer; + + const grainGain = offlineCtx.createGain(); + grainSource.connect(grainGain); + grainGain.connect(offlineCtx.destination); + + applyHannWindowFast (grainGain, now + outputTime, grainDuration); + + grainSource.start(now + outputTime, offset, grainDuration); + filter_chain.push (grainGain); + temp_source[grainIndex] = grainSource; + + ++grainIndex; + } + + return (filter_chain); + }, + + destroy : function () { + temp_source = []; + }, + + update : function ( filter_chain, audio_ctx, val, source ) { + prev_val = 1 / val; + var fx_buffer = source.buffer; + + let grainDuration = 0.05; // 50 ms grain + const analysisHop = 0.025; // 25 ms step (50% overlap) + const desiredOverlap = 0.5; // 50% overlap + const synthesisHop = analysisHop * prev_val; // output hop + + if (prev_val > 1) { + grainDuration = synthesisHop / (1 - desiredOverlap); // 0.15 sec (150 ms + } + + const now = audio_ctx.currentTime; + + // var filter = fx.filter ( offlineCtx, offlineCtx.destination, null, duration ); + var applyHannWindowFast = function (gainNode, outputTime, grainDuration) { + // The automation curve using a Hann window shape + const numSteps = 50; + + for (let i = 0; i <= numSteps; i++) { + const t = (i / numSteps) * grainDuration; + const windowValue = 0.5 * (1 - Math.cos((2 * Math.PI * t) / grainDuration)); + gainNode.gain.linearRampToValueAtTime(windowValue, outputTime + t); + } + }; + + // Schedule grains + var l = filter_chain.length; + var t = 0; + for (var i = 0; i < l; ++i) { + const offset = t; + const outputTime = i * synthesisHop; + //if (offset + grainDuration > fx_buffer.duration) break; + const grainGain = filter_chain[i]; + let grainSource = temp_source[i]; + grainSource.stop(); + + grainSource = audio_ctx.createBufferSource(); + grainGain.gain.setValueAtTime(grainGain.gain.value, now); + grainGain.gain.cancelScheduledValues(now); + + grainSource.buffer = fx_buffer; + grainSource.connect(grainGain); + temp_source[i] = grainSource; + + applyHannWindowFast (grainGain, outputTime + now, grainDuration); + + grainSource.start(now + outputTime, offset, grainDuration); + t += analysisHop; + } + // -- + } + }; + }, + + Speed : function ( val ) { + var prev_val = 1.0; + + return { + filter : function ( audio_ctx, destination, source, duration ) { + + var inputNode = audio_ctx.createGain(); + + source.playbackRate.value = val; + source.connect (inputNode); + + // line in to dry mix + inputNode.connect (destination); + + var filter_chain = [ inputNode ]; + + return (filter_chain); + }, + + preview: function (state, source) { + if (!state) source.playbackRate.value = 1.0; + else source.playbackRate.value = prev_val; + }, + + update : function ( filter_chain, audio_ctx, val, source ) { + prev_val = val; + source.playbackRate.value = val; + } + }; + }, + + Delay : function ( val ) { + return { + filter : function ( audio_ctx, destination, source, duration ) { + + var inputNode = audio_ctx.createGain(); + var outputNode = audio_ctx.createGain(); + var dryGainNode = audio_ctx.createGain(); + var wetGainNode = audio_ctx.createGain(); + var feedbackGainNode = audio_ctx.createGain(); + var delayNode = audio_ctx.createDelay(); + + source.connect (inputNode); + + // line in to dry mix + inputNode.connect (dryGainNode); + // dry line out + dryGainNode.connect (outputNode); + + // feedback loop + delayNode.connect (feedbackGainNode); + feedbackGainNode.connect (delayNode); + + // line in to wet mix + inputNode.connect (delayNode); + // wet out + delayNode.connect (wetGainNode); + + // wet line out + wetGainNode.connect (outputNode); + outputNode.connect (destination); + + var filter_chain = [ inputNode, outputNode, dryGainNode, + wetGainNode, feedbackGainNode, delayNode ]; + + if (!val.delay.length) + delayNode.delayTime.value = val.delay.val; + else { + for (var i = 0; i < val.delay.length; ++i) { + delayNode.delayTime.linearRampToValueAtTime (val.delay[i].val, val.delay[i].time + audio_ctx.currentTime ); + } + } + + if (!val.feedback.length) + feedbackGainNode.gain.value = val.feedback.val; + else { + for (var i = 0; i < val.feedback.length; ++i) { + feedbackGainNode.gain.linearRampToValueAtTime (val.feedback[i].val, val.feedback[i].time + audio_ctx.currentTime ); + } + } + + if (!val.mix.length) { + dryGainNode.gain.value = 1 - ((val.mix.val - 0.5) * 2); + wetGainNode.gain.value = 1 - ((0.5 - val.mix.val) * 2); + } + else { + for (var i = 0; i < val.mix.length; ++i) { + dryGainNode.gain.linearRampToValueAtTime (1 - ((val.mix[i].val - 0.5) * 2), val.mix[i].time + audio_ctx.currentTime ); + wetGainNode.gain.linearRampToValueAtTime (1 - ((0.5 - val.mix[i].val) * 2), val.mix[i].time + audio_ctx.currentTime ); + } + } + + return (filter_chain); + }, + + update : function ( filter_chain, audio_ctx, val ) { + // update filter chain... + var inputNode = filter_chain[0]; + var outputNode = filter_chain[1]; + var dryGainNode = filter_chain[2]; + var wetGainNode = filter_chain[3]; + var feedbackGainNode = filter_chain[4]; + var delayNode = filter_chain[5]; + + if (!val.delay.length) + delayNode.delayTime.value = val.delay.val; + else { + for (var i = 0; i < val.delay.length; ++i) { + delayNode.delayTime.linearRampToValueAtTime (val.delay[i].val, val.delay[i].time + audio_ctx.currentTime ); + } + } + + if (!val.feedback.length) + feedbackGainNode.gain.value = val.feedback.val; + else { + for (var i = 0; i < val.feedback.length; ++i) { + feedbackGainNode.gain.linearRampToValueAtTime (val.feedback[i].val, val.feedback[i].time + audio_ctx.currentTime ); + } + } + + if (!val.mix.length) { + dryGainNode.gain.value = 1 - ((val.mix.val - 0.5) * 2); + wetGainNode.gain.value = 1 - ((0.5 - val.mix.val) * 2); + } + else { + for (var i = 0; i < val.mix.length; ++i) { + dryGainNode.gain.linearRampToValueAtTime (1 - ((val.mix[i].val - 0.5) * 2), val.mix[i].time + audio_ctx.currentTime ); + wetGainNode.gain.linearRampToValueAtTime (1 - ((0.5 - val.mix[i].val) * 2), val.mix[i].time + audio_ctx.currentTime ); + } + } + // --- + } + }; + }, + + Distortion : function ( val ) { + return { + filter : function ( audio_ctx, destination, source, duration ) { + + var wave_shaper = audio_ctx.createWaveShaper (); + // var gain = parseInt (0.5 * 100, 10); + var compute_dist = function ( val ) { + var gain = parseInt ( (val / 1) * 100, 10); + var n_samples = 44100; + var curve = new Float32Array (n_samples); + var deg = Math.PI / 180; + var x; + + for (var i = 0; i < n_samples; ++i ) { + x = i * 2 / n_samples - 1; + curve[i] = (3 + gain) * x * 20 * deg / (Math.PI + gain * Math.abs(x)); + } + + return (curve); + }; + + + for (var k = 0; k < val.length; ++k) + { + var curr = val[k]; + if (curr.length) + { + for (var i = 0; i < curr.length; ++i) { + wave_shaper.curve.linearRampToValueAtTime (compute_dist(curr[i].val), audio_ctx.currentTime + curr[i].time); + } + } + else + { + wave_shaper.curve = compute_dist (curr.val); + } + } + + source.connect (wave_shaper); + wave_shaper.connect (destination); + + return (wave_shaper); + }, + + update : function ( filter, audio_ctx, val ) { + + var compute_dist = function ( val ) { + var gain = parseInt ( (val / 1) * 100, 10); + var n_samples = 44100; + var curve = new Float32Array (n_samples); + var deg = Math.PI / 180; + var x; + + for (var i = 0; i < n_samples; ++i ) { + x = i * 2 / n_samples - 1; + curve[i] = (3 + gain) * x * 20 * deg / (Math.PI + gain * Math.abs(x)); + } + + return (curve); + }; + + + for (var k = 0; k < val.length; ++k) + { + var curr = val[k]; + if (curr.length) + { + for (var i = 0; i < curr.length; ++i) { + filter.curve.linearRampToValueAtTime (compute_dist(curr[i].val), audio_ctx.currentTime + curr[i].time); + } + } + else + { + filter.curve = compute_dist (curr.val); + } + } + // ---- + } + }; + }, + + Reverb : function ( val ) { + return { + filter : function ( audio_ctx, destination, source, duration ) { + // ---- + var inputNode = audio_ctx.createGain(); + var reverbNode = audio_ctx.createConvolver(); + var outputNode = audio_ctx.createGain(); + var wetGainNode = audio_ctx.createGain(); + var dryGainNode = audio_ctx.createGain(); + + source.connect (inputNode); + + inputNode.connect (reverbNode); + reverbNode.connect (wetGainNode); + inputNode.connect (dryGainNode); + dryGainNode.connect (outputNode); + wetGainNode.connect (outputNode); + outputNode.connect (destination); + + var filter_chain = [ inputNode, outputNode, reverbNode, dryGainNode, wetGainNode ]; + + // set defaults + dryGainNode.gain.value = 1 - ((val.mix - 0.5) * 2); + wetGainNode.gain.value = 1 - ((0.5 - val.mix) * 2); + + var length = audio_ctx.sampleRate * val.time; + var impulse = audio_ctx.createBuffer (2, length, audio_ctx.sampleRate); + var impulseL = impulse.getChannelData(0); + var impulseR = impulse.getChannelData(1); + var n, i; + + for (i = 0; i < length; i++) { + n = val.reverse ? length - i : i; + impulseL[i] = (Math.random() * 2 - 1) * Math.pow(1 - n / length, val.decay); + impulseR[i] = (Math.random() * 2 - 1) * Math.pow(1 - n / length, val.decay); + } + reverbNode.buffer = impulse; + + return (filter_chain); + }, + + update : function ( filter_chain, audio_ctx, val ) { + + audio_ctx = wavesurfer.backend.ac; + + var reverbNode = filter_chain[2]; + var dryGainNode = filter_chain[3]; + var wetGainNode = filter_chain[4]; + + dryGainNode.gain.value = 1 - ((val.mix - 0.5) * 2); + wetGainNode.gain.value = 1 - ((0.5 - val.mix) * 2); + + var length = audio_ctx.sampleRate * val.time; + var impulse = audio_ctx.createBuffer (2, length, audio_ctx.sampleRate); + var impulseL = impulse.getChannelData(0); + var impulseR = impulse.getChannelData(1); + var n, i; + + for (i = 0; i < length; i++) { + n = val.reverse ? length - i : i; + impulseL[i] = (Math.random() * 2 - 1) * Math.pow(1 - n / length, val.decay); + impulseR[i] = (Math.random() * 2 - 1) * Math.pow(1 - n / length, val.decay); + } + reverbNode.buffer = impulse; + } + }; + } + }; + + + this.FXPreviewUpdate = updatePreview; + this.FXPreviewStop = stopPreview; + this.FXPreviewToggle = togglePreview; + this.FXPreviewInit = initPreview; + this.FXPreview = previewEffect; + this.FX = applyEffect; + this.FXBank = FXBank; + + this.Trim = TrimBuffer; + this.Copy = CopyBufferSegment; + this.Insert = InsertSegmentToBuffer; + this.InsertFloatArrays = InsertFloatArrays; + this.ReplaceFloatArrays = ReplaceFloatArrays; + this.Replace = OverwriteBufferWithSegment; + this.FullReplace = OverwriteBuffer; + this.MakeSilence = MakeSilenceBuffer; + this.DownloadFile = DownloadFile; + this.DownloadFileCancel = DownloadFileCancel; + // this.ComputeTopFrequencies = findTopFrequencies; + // this.MatchTopFrequencies= killdTopFrequencies; + // --- + }; + + PKAE._deps.audioutils = AudioUtils; +})( PKAudioEditor ); \ No newline at end of file diff --git a/audiomass-editor/src/app.js b/audiomass-editor/src/app.js new file mode 100755 index 0000000..836e216 --- /dev/null +++ b/audiomass-editor/src/app.js @@ -0,0 +1,107 @@ +(function (w, d) { + 'use strict'; + + var _v = '0.9', + _id = -1; + + function PKAE() { + var q = this; // keeping track of current context + + q.el = null; // reference of main html element + q.id = ++_id; // auto incremental id + q._deps = {}; // dependencies + + w.PKAudioList[q.id] = q; + + var events = {}; + + q.fireEvent = function (eventName, value, value2) { + var group = events[eventName]; + if (!group) return (false); + + var l = group.length; + while (l-- > 0) { + group[l] && group[l](value, value2); + } + }; + + q.listenFor = function (eventName, callback) { + if (!events[eventName]) + events[eventName] = [callback]; + else + events[eventName].unshift(callback); + }; + + q.stopListeningFor = function (eventName, callback) { + var group = events[eventName]; + if (!group) return (false); + + var l = group.length; + while (l-- > 0) { + if (group[l] && group[l] === callback) { + group[l] = null; break; + } + } + }; + + q.stopListeningForName = function (eventName) { + var group = events[eventName]; + if (!group) return (false); + events[eventName] = null; + }; + + q.init = function (el_id) { + var el = d.getElementById(el_id); + if (!el) { + console.log('invalid element'); + return; + } + q.el = el; + + // init libraries + q.ui = new q._deps.ui(q); q._deps.uifx(q); + q.engine = new q._deps.engine(q); + q.state = new q._deps.state(4, q); + q.rec = new q._deps.rec(q); + q.fls = new q._deps.fls(q); + + if (w.location.href.split('local=')[1]) { + var sess = w.location.href.split('local=')[1]; + + q.fls.Init(function () { + q.fls.GetSession(sess, function (e) { + if (e && e.id === sess) { + q.engine.LoadDB(e); + } + }); + }); + } + + // Check for audioUrl parameter to load audio from URL + if (w.location.href.split('audioUrl=')[1]) { + var audioUrl = decodeURIComponent(w.location.href.split('audioUrl=')[1].split('&')[0]); + + setTimeout(function () { + if (audioUrl) { + q.engine.LoadURL(audioUrl); + } + }, 500); + } + + return (q); + }; + + // check if we are mobile and hide tooltips on hover + q.isMobile = (/iphone|ipod|ipad|android/).test + (navigator.userAgent.toLowerCase()); + }; + + !w.PKAudioList && (w.PKAudioList = []); + + // ideally we do not want a global singleto refferencing our audio tool + // but since this is a limited demo we can safely do it. + w.PKAudioEditor = new PKAE(); + + PKAudioList.push(w.PKAudioEditor); // keeping track in the audiolist array of our instance + +})(window, document); \ No newline at end of file diff --git a/audiomass-editor/src/audiomass-server.go b/audiomass-editor/src/audiomass-server.go new file mode 100755 index 0000000..692b3a7 --- /dev/null +++ b/audiomass-editor/src/audiomass-server.go @@ -0,0 +1,49 @@ +package main + +import ( + "net/http" + _ "net/url" + "fmt" + "os/exec" + "strings" + "time" +) + +func main() { + + changeHeaderThenServe := func(h http.Handler) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Access-Control-Allow-Origin", "*") + + if strings.Contains(r.URL.Path, ".wasm") { + w.Header().Add("Content-Type", "application/wasm") + } + + if strings.Contains(r.URL.Path, ".js") { + var epoch = time.Unix(0, 0).Format(time.RFC1123) + var noCacheHeaders = map[string]string{ + "Expires": epoch, + "Cache-Control": "no-cache, private, max-age=0", + "Pragma": "no-cache", + "X-Accel-Expires": "0", + } + + for k, v := range noCacheHeaders { + w.Header().Set(k, v) + } + } + + fmt.Println("Req:", r.Host, r.URL.Path) + h.ServeHTTP(w, r) + } + } + + go func() { + cmd := exec.Command("open", "-a", "Google Chrome", "http://localhost:5055/") + cmd.Output() + }() + + fmt.Printf("\nListening on http://localhost:5055 \n\n") + http.Handle("/", changeHeaderThenServe(http.FileServer(http.Dir(".")))) + panic(http.ListenAndServe(":5055", nil)) +} \ No newline at end of file diff --git a/audiomass-editor/src/audiomass-server.py b/audiomass-editor/src/audiomass-server.py new file mode 100644 index 0000000..15ae2c1 --- /dev/null +++ b/audiomass-editor/src/audiomass-server.py @@ -0,0 +1,7 @@ +import SimpleHTTPServer +import SocketServer +PORT = 5055 +Handler = SimpleHTTPServer.SimpleHTTPRequestHandler +httpd = SocketServer.TCPServer(("", PORT), Handler) +print "serving at port", PORT +httpd.serve_forever() \ No newline at end of file diff --git a/audiomass-editor/src/audiomass-url-patch.js b/audiomass-editor/src/audiomass-url-patch.js new file mode 100644 index 0000000..c436601 --- /dev/null +++ b/audiomass-editor/src/audiomass-url-patch.js @@ -0,0 +1,12 @@ +// Add this to app.js after line 78 (after the local= parameter check) + +// Check for audioUrl parameter to load audio from URL +if (w.location.href.split('audioUrl=')[1]) { + var audioUrl = decodeURIComponent(w.location.href.split('audioUrl=')[1].split('&')[0]); + + setTimeout(function () { + if (audioUrl) { + q.engine.LoadURL(audioUrl); + } + }, 500); +} diff --git a/audiomass-editor/src/audiomass.appcache b/audiomass-editor/src/audiomass.appcache new file mode 100755 index 0000000..0ed31d8 --- /dev/null +++ b/audiomass-editor/src/audiomass.appcache @@ -0,0 +1,38 @@ +CACHE MANIFEST +# v1 - July 26, 2018 +# v2 - May 25, 2020 + +/index-cache.html +/main.css +/dist/wavesurfer.js +/dist/plugin/wavesurfer.regions.js +/oneup.js +/app.js +/keys.js +/contextmenu.js +/ui-fx.js +/ui.js +/modal.js +/state.js +/engine.js +/actions.js +/drag.js +/recorder.js +/welcome.js +/fx-pg-eq.js +/fx-auto.js +/local.js +/id3.js +/lzma.js +/lame.js +/fonts/icomoon.ttf +/fonts/icomoon.woff +/test.mp3 + + +NETWORK: +/index-cache.html + +# Fallback content +FALLBACK: +. /index-cache.html diff --git a/audiomass-editor/src/contextmenu.js b/audiomass-editor/src/contextmenu.js new file mode 100755 index 0000000..7ba18ac --- /dev/null +++ b/audiomass-editor/src/contextmenu.js @@ -0,0 +1,205 @@ +(function ( win, doc, PKAE ) { + 'use strict'; + + var activeMenu = [], + namespace = win, + contextStorage = {}, + _id = 0; + + var closeEvent = [ 'mousedown', 'touchup' ]; + + /** + * Goes through every single context instance and terminates + * it. + **/ + var closeContext = function ( e, force ) { + if (!e) return ; + if (activeMenu.length === 0) return ; + + var el = e.target || e.srcElement; + + if (!el || el.className.indexOf('_action') === -1 || force) + { + var l = activeMenu.length; + while (l--) terminate (activeMenu[ l ]); + activeMenu = []; + } + }, + /** + * Go through every children element of the context el, + * and remove all listeners and added attributes, then remove it + * from the dom also + **/ + terminate = function( e ) { + var children = e.currentMenu.getElementsByTagName('*'), + len = children.length; + + while( len-- ) + children[ len ].parentNode.removeChild( children[ len ] ); + + e.currentMenu.removeEventListener( closeEvent, stopPropagation ); + doc.body.removeChild( e.currentMenu ); + e.currentMenu = null; + return false; + }, + /** stop propagation func, so that we don't have to use anonymous funcs **/ + stopPropagation = function(e){ e.stopPropagation(); }, + openContext = function( e, x, y ) { + + closeContext(null); + activeMenu.push( e ); + + //go through all the options and make the div + var div = doc.createElement('div'), + a, + marginOffset = 4, + opts = e.options, + leftOffset = x - marginOffset, + topOffset = y - marginOffset, + width = 0, height = 0; + + div.className = "pk_contextMenu " + e.menuClass; + div.id = e.token; + + for( var i = 0, len = opts.length; i < len; ++i ) { + if( opts[ i ].isHTML ) + { + a = doc.createElement('div'); + a.innerHTML = opts[ i ].isHTML; + div.appendChild( a ); + } + else { + a = doc.createElement('a'); + a.className = 'pk_ctx_action'; + a.cnt = 1; + a.innerHTML = opts[ i ].name; + a.callback = opts[ i ].callback; + + a.addEventListener( 'click', a.callback, false ); + + div.appendChild( a ); + } + } + + e.currentMenu = div; + div.addEventListener( closeEvent, stopPropagation, false ); + + doc.body.appendChild( div ); + + width = div.offsetWidth; + height = div.offsetHeight; + + if( win.innerWidth < ( leftOffset + width ) && win.innerHeight < ( topOffset + height ) ) + div.style.cssText = "top:" + ( topOffset - height ) + "px;left:" + ( leftOffset - width ) + "px;"; + else if( win.innerWidth < ( leftOffset + width ) ) + div.style.cssText = "top:" + ( topOffset ) + "px;left:" + ( leftOffset - width ) + "px;"; + else if( win.innerHeight < ( topOffset + height ) ) + div.style.cssText = "top:" + ( topOffset - height ) + "px;left:" + ( leftOffset ) + "px;"; + else + div.style.cssText = "top:" + ( topOffset ) + "px;left:" + ( leftOffset ) + "px;"; + + if (e.onOpen) { + e.onOpen ( e, div ); + } + + return false; + }, + openMenu = function( e ) + { + if (e) { + e.preventDefault(); + e.stopPropagation(); + } + else { + e = {pageX:0, pageY:0}; + } + + // ---- + var instance = getInstance ( this ); + var pageX = e.pageX || e.clientX + doc.documentElement.scrollLeft; + var pageY = e.pageY || e.clientY + doc.documentElement.scrollTop; + + if (!instance) return false; + + instance.curr_target = e.target || e.srcElement; + + openContext ( instance, pageX, pageY ); + }, + getInstance = function( elem ) { + return contextStorage[ elem.getAttribute( 'data-token' ) ]; + }; + + /** + * Context Menu Constructor + **/ + var contextMenu = namespace.contextMenu = function( elem, options ) { + if (!(this instanceof contextMenu)) return new contextMenu( elem, options ); + if (!options) options = {}; + + var open_events = ['contextmenu', 'longpress']; + + this.elem = elem; + this.options = []; + this.menuClass = options.className || 'pk_open'; + this.curr_target = null; + + // modified context menu to open only when double click + no movement + // if (elem) elem.addEventListener( 'contextmenu', openMenu, false ); + if (elem) elem.addEventListener( 'pk_ctxmn', openMenu, false ); + + this.token = ++_id; + if (elem) elem.setAttribute( 'data-token', this.token ); + + contextStorage[ this.token ] = this; + }; + /** + * Wrapper to the private openMenu function + **/ + contextMenu.prototype.open = function( e ) { + openMenu.call( this.elem, e ); + }; + contextMenu.prototype.close = function( e ) { + closeContext(); + }; + contextMenu.prototype.openWithToken = function( token, x, y ) { + openContext( contextStorage[ token ], x||0, y||0 ); + }; + /** + * Closes context and removes it fully + **/ + contextMenu.prototype.destroy = function() { + // this.elem.removeEventListener( 'contextmenu', openMenu ); + this.elem.removeEventListener( 'pk_ctxmn', openMenu ); + + closeContext(); + contextStorage[ this.token ] = null; + + return false; + }, + /** + * Adds option + * @param string name of the option + * @param function to run when its chosen + * @param if this is set, then append the HTML instead of its name in its position + * @param initialization code to run when the object is appended to the dom + **/ + contextMenu.prototype.addOption = function( name, callback, isHTML ) { + var q = this; + this.options.push({ "name" : name, "callback" : function( e ) { + + callback && callback( q, q._open ); + closeContext( q, true ); + }, + "isHTML" : isHTML + }); + }; + + + // todo touch controls too? #### + doc.addEventListener( closeEvent[0], closeContext, false ); + doc.addEventListener( 'killCTX', closeContext, false ); + + + PKAE._deps.ContextMenu = contextMenu; + +})( window, document, PKAudioEditor ); \ No newline at end of file diff --git a/audiomass-editor/src/drag.js b/audiomass-editor/src/drag.js new file mode 100755 index 0000000..4690323 --- /dev/null +++ b/audiomass-editor/src/drag.js @@ -0,0 +1,178 @@ +(function( parent ) { + 'use strict'; + + /** parent object, set in the end of the selfcalling function **/ + var parent = parent || window, + /** instance of File Reader **/ + reader, + readFile, + /** + * Removes class from element + * @param htmlObject target element + * @param string "class to be removed" + **/ + removeClass = function( el, value ) { + if ( !el.className ) return false; + var classes = el.className.split(' '), + ret = []; + for( var i = 0, l = classes.length; i < l; ++i ) + if( classes[i] != value ) + ret.push( classes[ i ] ); + el.className = ret.join(' '); + }; + + if( !window.FileReader || !document.addEventListener ) { + throw( "File API not supported" ); + readFile = function(){ throw( "File API not supported" ); }; + } + else { + reader = new FileReader(); + readFile = function ( file, callback, method ) { + /** Error handler (throws error at the console) **/ + reader.onerror = function( e ) { + var message, + lut = [ "File not found.", "File coulnot be opened", + "File couldnot be uploaded", "Couldnot read File", "File too large" ]; + // http://www.w3.org/TR/FileAPI/#ErrorDescriptions + throw( lut[ ( e.target.error.code - 1 ) ] ); + }, + /** Success, calling the callback **/ + reader.onloadend = function( e ) { + callback && callback( e.target.result, file.name ); + reader.onloadend = null; + }; + + // the method is specified in the beginning of the file + reader[ method ]( file ); + return false; + }; + } + + /** + * Drag n Drop Files module + * @param HTMLElement, could be the Body + * @param DOMElement/String, if a string is specified then a div will be built and appended to the body + * with that String as its id. If a dom element is passed, that will be used instead. This object + * acts as an overlay and the file should be droped to this object. If this object is null, then the first argument + * will be used as the overlay. + * @param Function, will be called with the file data, and the filename as its arguments + * @param String, possible values "text, binarytext, arrabuffer" decides how the file will be read + * if let null, defaults to text + * @param String, class name to be added to the overlay (default is '__fadingIn') + **/ + parent.dragNDrop = function( body, overlay_id, callback, method, _clss ) { + var win = window; + // check to see if we are using a mobile device - no need for dragNdrop in devices + // that do not support it somehow yet + if( ( 'ontouchstart' in window ) ) + return "mobile"; + + /** JS Object, used to define the file-reading method **/ + var method_lut = { + 'text' : 'readAsText', + 'binary' : 'readAsBinaryText', + 'arrayBuffer': 'readAsArrayBuffer' + }, + /** class added/removed from overlay object **/ + clss = _clss ? _clss : "__fadingIn", + method = method ? method_lut[ method ] : 'readAsText', + /** how many events cast (dragenter/dragleave) **/ + entered = 0, + /** + * DOMElement sink for the drag events + * if left unspecified then the body inherits the role + **/ + overlay = !!overlay_id ? overlay_id : body, + /** + * (void) if the overlay_id specified is a string, then a div with that id is built + * and appended to the body. Else the default is used + **/ + _overlayBuilder = function() { + if( typeof overlay_id === "string" ) + { + var tmp = document.createElement( 'div' ); + overlay = document.createElement( 'div' ); + overlay.id = overlay_id; + + tmp.innerHTML = "Drag n drop Files!"; + overlay.appendChild( tmp ); + + body.appendChild( overlay ); + tmp = null; + } + }, + /** + * JS Object + * The events Object contains various functions that control + * the behavior of the events fired + **/ + events = { + /** + * (void) Prevents default action and bubbling up + **/ + silencer : function( e ) { + e.preventDefault(); + e.stopPropagation() + }, + + /** + * Shows message to drop file + **/ + onDragEnter : function( e ) { + // overlay.className += " " + clss; + ++entered; + + setTimeout(function() { + if( entered > 1 ) + entered = 1; + }, 10 ) + }, + /** + * Hides the overlay... twist included! + **/ + onDragLeave : function( e ) { + --entered; + + if( entered <= 0 ) + { + removeClass( overlay, clss ); + entered = 0; + } + }, + /** + * Files dropped + **/ + onDrop : function( e ) { + // prevent the event from bubbling/firing default + events.silencer( e ); + + // Hide the overlay + removeClass( overlay, clss ); + entered = 0; + + /** dropped files. **/ + var files = e.dataTransfer.files, + len; + + // If anything is wrong with the dropped files, exit. + if( !files || !files.length ) + return false; + + len = files.length; + while( len-- ) + // iterate files array and load them + readFile( files[ len ], callback, method ); + } + }; + + (function init() { + //_overlayBuilder(); + // events initialization + body.parentNode.addEventListener( "dragenter", events.onDragEnter, false ); + body.addEventListener( "dragleave", events.onDragLeave, false ); + body.addEventListener( "dragover", events.silencer, false); + body.addEventListener( "drop", events.onDrop, false); + return false; + })( body ); + }; +})( window ); \ No newline at end of file diff --git a/audiomass-editor/src/engine.js b/audiomass-editor/src/engine.js new file mode 100755 index 0000000..2d07f88 --- /dev/null +++ b/audiomass-editor/src/engine.js @@ -0,0 +1,2904 @@ +(function ( w, d, PKAE ) { + 'use strict'; + + function PKEng ( app ) { + var q = this; + + var wavesurfer = WaveSurfer.create ({ + container: '#' + 'pk_av_' + app.id, + scrollParent: false, + hideScrollbar:true, + partialRender:false, + fillParent:false, + pixelRatio:1, + progressColor:'rgba(128,85,85,0.24)', + splitChannels:true, + autoCenter:true, + height:w.innerHeight - 168, + plugins: [ + WaveSurfer.regions.create({ + dragSelection: { + slop: 5 + } + }) + ] + }); + this.wavesurfer = wavesurfer; + + var AudioUtils = new app._deps.audioutils ( app, wavesurfer ); + q.is_ready = false; + + this.TrimTo = function( val, num ) { + var nums = {'0':1, '1':10, '2':100,'3':1000,'4':10000,'5':100000}; + var dec = nums[num]; + return ((val *dec) >> 0) / dec; + } + + this.LoadArrayBuffer = function ( e ) { + var func = function () { + app.listenFor ('RequestCancelModal', function() { + wavesurfer.cancelBufferLoad (); + if (wavesurfer.arraybuffer) q.is_ready = true; + + app.fireEvent ('RequestResize'); + setTimeout(function() { app.fireEvent ('DidDownloadFile'); }, 12); + app.stopListeningForName ('RequestCancelModal'); + + OneUp ('Canceled Loading', 1350); + }); + + app.fireEvent ('RequestZoomUI', 0); + + app.fireEvent ('WillDownloadFile'); + q.is_ready = false; + wavesurfer.loadBlob( e ); + app.fireEvent ('DidUnloadFile'); + + wavesurfer.regions && wavesurfer.regions.clear(); + }; + + if ( q.is_ready ) + { + // ---------------- + new PKSimpleModal ({ + title : 'Open or append', + clss : 'pk_modal_anim pk_fnt10', + ondestroy : function ( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback ('modalTempErr'); + }, + buttons:[ + { + title:'OPEN NEW', + callback: function( q ) { + wavesurfer.backend._add = 0; + func (); + q.Destroy (); + } + }, + { + title:'ADD IN EXISTING', + callback: function( q ) { + wavesurfer.backend._add = 1; + func (); + q.Destroy (); + } + } + ], + body : '

Append file to existing track?

', + setup : function( q ) { + app.ui.InteractionHandler.checkAndSet ('modal'); + app.ui.KeyHandler.addCallback ('modalTempErr', function ( e ) { + q.Destroy (); + }, [27]); + } + }).Show (); + + return ; + } + + wavesurfer.backend._add = 0; + func (); + // --- + }; + + this.LoadDB = function ( e ) { + var new_buffer = wavesurfer.backend.ac.createBuffer ( + e.data.length, + e.data[0].byteLength / 4, + e.samplerate + ); + + for (var i = 0; i < e.data.length; ++i) { + + var arr = new Float32Array (e.data[i]); + + if (new_buffer.copyToChannel) + { + new_buffer.copyToChannel (arr, i, 0); + } + else + { + var chan = new_buffer.getChannelData (i); + chan.set (arr); + } + } + + var append = wavesurfer.backend._add; + var old_durr = wavesurfer.getDuration (); + + PKAudioEditor.engine.wavesurfer.loadDecodedBuffer (new_buffer); + _compute_channels (); + var new_durr = wavesurfer.getDuration (); + app.fireEvent ('DidUpdateLen', new_durr); + + if (!append) app.fireEvent ('RequestSeekTo', 0); + else { + wavesurfer.regions.clear(); + wavesurfer.regions.add({ + start:old_durr, + end:new_durr, + id:'t' + }); + } + // -------- + }; + + this.LoadFile = function ( e ) { + if (e.files.length > 0) + { + if (e.files[0].type == "audio/mp3" + || e.files[0].type == "audio/wave" + || e.files[0].type == "audio/mpeg" + || e.files[0].type == "audio/aiff" + || e.files[0].type == "audio/flac" + || e.files[0].type == "audio/ogg") + { + + var func = function () { + app.listenFor ('RequestCancelModal', function() { + wavesurfer.cancelBufferLoad (); + AudioUtils.DownloadFileCancel (); + if (wavesurfer.arraybuffer) q.is_ready = true; + + app.fireEvent ('RequestResize'); + setTimeout(function() { + app.fireEvent ('DidDownloadFile'); + }, 12); + app.stopListeningForName ('RequestCancelModal'); + + OneUp ('Canceled Loading', 1350); + }); + + app.fireEvent ('WillDownloadFile'); + q.is_ready = false; + wavesurfer.loadBlob( e.files[0] ); + app.fireEvent ('DidUnloadFile'); + wavesurfer.regions && wavesurfer.regions.clear(); + }; + + if ( q.is_ready ) + { + // ---------------- + new PKSimpleModal ({ + title : 'Open or append', + clss : 'pk_modal_anim pk_fnt10', + ondestroy : function ( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback ('modalTempErr'); + }, + buttons:[ + { + title:'OPEN NEW', + callback: function( q ) { + wavesurfer.backend._add = 0; + func (); + q.Destroy (); + } + }, + { + title:'ADD IN EXISTING', + callback: function( q ) { + wavesurfer.backend._add = 1; + func (); + q.Destroy (); + } + } + ], + body : '

Append file to existing track?

', + setup : function( q ) { + app.ui.InteractionHandler.checkAndSet ('modal'); + app.ui.KeyHandler.addCallback ('modalTempErr', function ( e ) { + q.Destroy (); + }, [27]); + } + }).Show (); + + return ; + } + + wavesurfer.backend._add = 0; + func (); + + // ---- + } + } + }; + + this.DownloadFile = function ( name, format, kbps, selection, stereo ) { + if (!q.is_ready) return ; + + app.fireEvent ('WillDownloadFile'); + + app.listenFor ('RequestCancelModal', function() { + AudioUtils.DownloadFileCancel (); + if (wavesurfer.arraybuffer) q.is_ready = true; + + app.fireEvent ('RequestResize'); + setTimeout(function() { app.fireEvent ('DidDownloadFile'); }, 12); + app.stopListeningForName ('RequestCancelModal'); + }); + + setTimeout(function() { + AudioUtils.DownloadFile ( name, format, kbps, selection, stereo, function ( val ) { + if (val === 'done') + { + setTimeout(function() { app.fireEvent ('DidDownloadFile'); }, 12); + app.stopListeningForName ('RequestCancelModal'); + } + else + app.fireEvent ('DidProgressModal', val); + }); + }, 220); + } + this.LoadSample = function () { + + app.fireEvent ('WillDownloadFile'); + + setTimeout(function () { + + app.listenFor ('RequestCancelModal', function() { + if (wavesurfer.cancelAjax ()) + { + if (wavesurfer.arraybuffer) q.is_ready = true; + + app.fireEvent ('RequestResize'); + setTimeout(function() { app.fireEvent ('DidDownloadFile'); }, 12); + app.stopListeningForName ('RequestCancelModal'); + + OneUp ('Canceled Loading', 1380); + } + }); + + app.fireEvent ('RequestZoomUI', 0); + q.is_ready = false; + wavesurfer.load ('test.mp3'); + }, 180); + } + this.LoadURL = function ( url ) { + app.fireEvent ('WillDownloadFile'); + + /* + var context = new AudioContext (); // wavesurfer.backend.ac; + var audio_el = d.createElement ('audio'); + audio_el.autoplay = true; + audio_el.controls = true; + audio_el.preload = true; +// audio_el.playbackRate = 0.5; + d.body.appendChild( audio_el ); + audio_el.src = url; + + setTimeout(function() { + var source = context.createMediaElementSource (audio_el); + // source.connect(context.destination); + + var time_duration = audio_el.duration / 1; + var first = true; + var audio_buffer = null; + var sample_rate = 0; + var chans = 0; + + var scriptNode = context.createScriptProcessor (4096, 1, 1); + window.sss = scriptNode; + window.eee = source; + window.ccc = context; + + var prev_time = 0; + + scriptNode.onaudioprocess = function( ev ) { + if (audio_el.paused) return ; + + var ctime = audio_el.currentTime / 1; + + if ((ctime + 0.0001) >= time_duration) + { + //if (!first) { + // console.log ("done"); + // first = 100; + //} + return ; + } + + var inputBuffer = ev.inputBuffer; + // var outputBuffer = ev.outputBuffer; + + if (first) { + first = false; + + sample_rate = inputBuffer.sampleRate; + chans = inputBuffer.numberOfChannels; + audio_buffer = context.createBuffer ( + inputBuffer.numberOfChannels, + time_duration * inputBuffer.sampleRate, + inputBuffer.sampleRate + ); + + window.audio_buffer = audio_buffer; + } + + var curr_time = (ctime * sample_rate) >> 0; + + // console.log( curr_time, " ", (curr_time - prev_time), " ", ((curr_time - prev_time) > (4096*2))?true:false ); + // prev_time = curr_time; + + for (var channel = 0; channel < inputBuffer.numberOfChannels; ++channel) { + var inputData = inputBuffer.getChannelData(channel); + // var outputData = outputBuffer.getChannelData(channel); + var final_data = audio_buffer.getChannelData(channel); + + // console.log( inputData ); + + // Loop through the 4096 samples + for (var sample = 0; sample < inputBuffer.length; ++sample) { + // make output equal to the same as the input + // outputData[sample] = inputData[sample]; + + final_data[curr_time + sample] = inputData[sample]; + + // add noise to each output sample + // outputData[sample] += ((Math.random() * 2) - 1) * 0.2; + } + } + }; + + source.connect(scriptNode); + scriptNode.connect(context.destination); + },2000); + */ + + setTimeout(function () { + app.listenFor ('RequestCancelModal', function() { + if (wavesurfer.cancelAjax()) + { + if (wavesurfer.arraybuffer) q.is_ready = true; + + app.fireEvent ('RequestResize'); + setTimeout(function() { app.fireEvent ('DidDownloadFile'); }, 12); + app.stopListeningForName ('RequestCancelModal'); + + OneUp ('Canceled Loading', 1350); + } + }); + + wavesurfer.load ( url ); + q.is_ready = false; + }, 180); + } + + app.listenFor ('RequestResize', function () { + wavesurfer.fireEvent ('resize'); + + var h = window.innerHeight; + var bottom = 0; + + if (app.ui && app.ui.BarBtm) { + bottom = (app.ui.BarBtm.on ? app.ui.BarBtm.height : 0); + } + + wavesurfer.setHeight( (h < 280 ? 280 : h) - 168 - bottom); + // app.fireEvent ('DidResize'); + }); + + wavesurfer.on ('ready', function () { + app.fireEvent ('DidReadyFire'); + + if (wavesurfer.backend._add) { + wavesurfer.backend._add = 0; + } + + if (q.is_ready) return ; + q.is_ready = true; + + // dirty hack for default message + var dirtymsg = document.getElementsByClassName('pk_tmpMsg'); + if (dirtymsg.length > 0) + { + dirtymsg = dirtymsg[0]; + dirtymsg.parentNode.removeChild( dirtymsg ); + } + + copy_buffer = null; + app.fireEvent ('DidDownloadFile'); + + app.fireEvent ('StateRequestClearAll'); + app.fireEvent ('DidLoadFile'); + app.fireEvent ('DidUpdateLen', wavesurfer.getDuration ()); + app.fireEvent ('DidSetClipboard', 0); + app.fireEvent ('RequestSeekTo', 0); + + app.fireEvent ('RequestResize'); + wavesurfer.getWaveEl().style.opacity = '1'; + + // loaded successfully + app.stopListeningForName ('RequestCancelModal'); + + setTimeout(function () {OneUp ('Loaded Successfully')}, 180); + + // check if the audio file is mono or stereo and rebuild both UI and audio engine accordingly... + if (wavesurfer.backend.buffer.numberOfChannels === 1) { + wavesurfer.backend.SetNumberOfChannels (1); + wavesurfer.ActiveChannels = [1]; + wavesurfer.drawer.params.ActiveChannels = wavesurfer.ActiveChannels; + wavesurfer.SelectedChannelsLen = 1; + + app.el.classList.add ('pk_mono'); + } else if (wavesurfer.backend.buffer.numberOfChannels === 2) { + wavesurfer.backend.SetNumberOfChannels (2); + wavesurfer.ActiveChannels = [1, 1]; + wavesurfer.drawer.params.ActiveChannels = wavesurfer.ActiveChannels; + wavesurfer.SelectedChannelsLen = 2; + + app.el.classList.remove ('pk_mono'); + } + // --- + }); + + wavesurfer.on ('pause', function() { + app.fireEvent ('DidStopPlay'); + }); + wavesurfer.on ('play', function() { + app.fireEvent ('DidPlay'); + }); + wavesurfer.on ('seek', function ( where, stamp ) { + var time = wavesurfer.getCurrentTime(); + var loudness = wavesurfer.getLoudness(); + + app.fireEvent ('DidAudioProcess', [time, loudness, stamp]); + }); + + app.listenFor ('RequestStop', function( val ) { + if (app.rec.isActive ()) { + app.fireEvent ('RequestActionRecordStop'); + return (false); + } + + var region = wavesurfer.regions.list[0]; + if (region) wavesurfer.ActiveMarker = region.start / wavesurfer.getDuration (); + + wavesurfer.stop ( val ); + }); + app.listenFor ('RequestPlay', function ( x ) { // unique listener + if (q.in_fx) return ; + + app.fireEvent ('RequestActionRecordStop'); + + if ( !x && wavesurfer.isPlaying ()) { + wavesurfer.stop (); + wavesurfer.play (); + } + else { + if (!app.rec.isActive ()) { + wavesurfer.play (); + } else { + setTimeout(function() { + if (!app.rec.isActive () && !x && !wavesurfer.isPlaying ()) { + wavesurfer.play (); + } + }, 220); + } + } + }); + app.listenFor ('RequestPause', function () { + app.fireEvent ('RequestActionRecordStop'); + wavesurfer.pause(); + }); + + app.listenFor ('RequestSetLoop', function () { + if (!q.is_ready) return ; + + var skip_seek = false; + + if (wavesurfer.regions.list[0]) + { + if (wavesurfer.regions.list[0].loop) + wavesurfer.regions.list[0].loop = false; + else + wavesurfer.regions.list[0].loop = true; + } + else + { + skip_seek = true; + wavesurfer.regions.add({ + start:0.01, + end:wavesurfer.getDuration() - 0.01, + id:'t' + }); + wavesurfer.regions.list[0].loop = true; + } + + var will_loop = wavesurfer.regions.list[0].loop; + app.fireEvent('DidSetLoop', will_loop); + if (will_loop && !skip_seek /*&& wavesurfer.isPlaying ()*/) { + app.fireEvent ('RequestSeekTo', wavesurfer.regions.list[0].start / wavesurfer.getDuration ()); + } + }); + app.listenFor ('RequestSkipBack', function( val ) { + wavesurfer.skipBackward ( val ) + }); + app.listenFor ('RequestSkipFront', function( val ) { + wavesurfer.skipForward ( val ); + }); + app.listenFor ('RequestSeekTo', function( val ) { + if (val > 1.0) return ; + wavesurfer.seekTo( val ); + }); + app.ui.KeyHandler.addCallback ('zkA', function ( key, m, e ) { + e.preventDefault (); + }, [38]); + app.ui.KeyHandler.addCallback ('zkD', function ( key, m, e ) { + e.preventDefault (); + }, [40]); + app.ui.KeyHandler.addSingleCallback ('KeyPlayPause', function ( e ) { + if (app.ui.InteractionHandler.on) return ; + e.preventDefault(); + //e.stopPropagation(); + }, 32); + + app.ui.KeyHandler.addSingleCallback ('KeyTilda', function ( e ) { + var open_el = app.ui.TopHeader.getOpenElement(); + + if (open_el) + { + app.ui.TopHeader.closeMenu (); + e.preventDefault(); + return ; + } + + if (app.ui.InteractionHandler.on) return ; + e.preventDefault(); + + app.ui.TopHeader.openMenu (-1); + }, 96); + + app.ui.KeyHandler.addSingleCallback ('KeyQ', function ( e ) { + if (app.ui.InteractionHandler.on) return ; + e.preventDefault(); + app.fireEvent ('RequestDeselect'); + }, 113); + + + app.ui.KeyHandler.addCallback ('kF12', function ( k, i, e ) { + e.preventDefault(); + e.stopPropagation(); + }, [123]); + /*app.ui.KeyHandler.addCallback ('kF5', function ( k, i, e ) { + e.preventDefault(); + e.stopPropagation(); + }, [116]); + */ + + app.ui.KeyHandler.addCallback ('KeyShiftSpace' + app.id, function ( key ) { + if (app.ui.InteractionHandler.on) return ; + wavesurfer.playPause(); + }, [16, 32]); + app.ui.KeyHandler.addCallback ('KeySpace' + app.id, function ( key, map ) { + if (app.ui.InteractionHandler.on) return ; + if (map[16] === 1) return ; + + if (PKAudioEditor.engine.wavesurfer.isPlaying()) + { + app.fireEvent ('RequestStop'); + } + else + { + app.fireEvent ('RequestPlay'); + } + }, [32]); + app.ui.KeyHandler.addCallback ('KeyShiftCopy' + app.id, function ( key ) { + if (app.ui.InteractionHandler.on) return ; + + app.fireEvent( 'RequestActionCopy'); + }, [16, 67]); + app.ui.KeyHandler.addCallback ('KeyShiftUndo' + app.id, function ( key ) { + if (app.ui.InteractionHandler.on) return ; + + app.fireEvent ('StateRequestUndo'); + }, [16, 90]); + app.ui.KeyHandler.addCallback ('KeyShiftRedo' + app.id, function ( key ) { + if (app.ui.InteractionHandler.on) return ; + + app.fireEvent ('StateRequestRedo'); + }, [16, 89]); + app.ui.KeyHandler.addCallback ('KeyShiftPaste' + app.id, function ( key ) { + if (app.ui.InteractionHandler.on) return ; + + app.fireEvent( 'RequestActionPaste'); + }, [16, 86]); + app.ui.KeyHandler.addCallback ('KeyShiftCut' + app.id, function ( key ) { + if (app.ui.InteractionHandler.on) return ; + + app.fireEvent( 'RequestActionCut', 1); + }, [16, 88]); + app.ui.KeyHandler.addCallback ('KeyDel' + app.id, function ( key ) { + if (app.ui.InteractionHandler.on) return ; + + app.fireEvent( 'RequestActionCut'); + }, [8]); + app.ui.KeyHandler.addCallback ('KeyShiftSelectAll' + app.id, function ( key ) { + if (app.ui.InteractionHandler.on) return ; + app.fireEvent ('RequestSelect'); + }, [16, 65]); + app.ui.KeyHandler.addSingleCallback ('KeyLoopToggle', function ( e ) { + if (app.ui.InteractionHandler.on) return ; + e.preventDefault(); + e.stopPropagation(); + app.fireEvent ('RequestSetLoop'); + }, 108); + app.ui.KeyHandler.addCallback ('KeyShiftSave' + app.id, function ( key ) { + if (app.ui.InteractionHandler.on) return ; + + // fire event to open the save menu + document.querySelector('.pk_opt[data-id="dl"]').click(); + }, [16, 83]); + + wavesurfer.container.addEventListener('mousedown', function(e) { + if (e.which === 3) { + // wavesurfer.regions.clear(); + e.preventDefault(); + } + },false); + + // select all... #### + app.listenFor ('RequestSelect', function( ifnot, custom ) { + if (!q.is_ready) return ; + + if (ifnot) + { + var region = wavesurfer.regions.list[0]; + if (region) return (false); + } + + if (!custom) + { + wavesurfer.regions.add({ + start:0.000, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + + if (!wavesurfer.isPlaying ()) + setTimeout(function () { + app.fireEvent ('RequestSeekTo', 0.00); + },0); + } + else + { + wavesurfer.regions.add({ + start:custom[0], + end:custom[1], + id:'t' + }); + if (!wavesurfer.isPlaying ()) + setTimeout(function () { + app.fireEvent ('RequestSeekTo', custom[0]/wavesurfer.getDuration ()); + },0); + } + }); + app.listenFor ('RequestDeselect', function() { + wavesurfer.regions.clear (); + app.fireEvent ('RequestSeekTo', 0); + }); + + (function() { + var input = null; + app.listenFor ('RequestLoadLocalFile', function () { + wavesurfer.pause(); + + if (input) + { + input.parentNode.removeChild( input ); + input.onchange = null; + } + + input = d.createElement( 'input' ); + input.setAttribute ('type', 'file'); + input.setAttribute ('accept', 'audio/*'); + input.className = 'pk_inpfile'; + input.onchange = function () { + q.LoadFile ( input ); + + input.parentNode.removeChild( input ); + input.onchange = null; + input = null; + }; + app.el.appendChild ( input ); // maybe not append? + + input.click (); + }); + })(); + + wavesurfer.container.addEventListener('dblclick', function(e){ + app.fireEvent ('RequestSelect', false, + [ wavesurfer.LeftProgress, + wavesurfer.LeftProgress + wavesurfer.VisibleDuration ] + ); + }, false); + wavesurfer.container.addEventListener ('click', function( e ) { + if (!q.is_ready) return ; + + if (!app.ui.KeyHandler.keyMap[16]) + wavesurfer.regions.clear(); + }, false); + + var dbncr = null; + w.addEventListener('resize', function() { + if (!wavesurfer) return ; + + if (dbncr) { + clearTimeout (dbncr); + } + + dbncr = setTimeout(function(){ + + //requestAnimationFrame(function (){ + app.fireEvent ('RequestResize'); + + if (app.isMobile) { + window.scrollTo (0, 200); + } + //}); + },84); + }, false); + +// w.addEventListener ('orientationchange', function () { +// app.fireEvent ('RequestResize'); +// }); + + w.addEventListener('beforeunload', function (e) { + app.fireEvent ('WillUnload'); + + // e.preventDefault(); + // e.returnValue = ''; + }); + + wavesurfer.on('error', function (error_msg) { + + // if loading - cancel loading + setTimeout(function() { + app.fireEvent ('DidDownloadFile'); // just hides the interface + q.is_ready = false; + }, 20); + + app.fireEvent ('ShowError', error_msg); + }); + + wavesurfer.on('audioprocess', function ( time, stamp ) { + // var time = wavesurfer.getCurrentTime(); + var loudness = wavesurfer.getLoudness(); + + app.fireEvent ('DidAudioProcess', [time, loudness, stamp], wavesurfer.backend.FreqArr); + }); + wavesurfer.on('DidZoom', function ( e ) { + app.fireEvent ('DidZoom', [wavesurfer.ZoomFactor, (wavesurfer.LeftProgress/wavesurfer.getDuration()) * 100, wavesurfer.params.verticalZoom], e); + }); + wavesurfer.on('region-removed', function (){ + app.fireEvent('DidSetLoop', 0); + app.fireEvent('DidDestroyRegion'); + }); + app.listenFor ('RequestRegionClear', function () { + wavesurfer.regions.clear(); + }); + app.listenFor ('RequestRegionSet', function ( start, end ) { + if (!q.is_ready) return ; + + if (!start) { + start = wavesurfer.LeftProgress / 1; + } + if (!end) { + end = (wavesurfer.LeftProgress + wavesurfer.VisibleDuration) / 1; + } + + // add a region where the paste happened + wavesurfer.regions.clear(); + wavesurfer.regions.add({ + start: start, + end: end, + id:'t' + }); + }); + + var copy_buffer = null; + + this.GetCopyBuff = function () { + return (copy_buffer); + }; + + this.GetSel = function () { + var region = wavesurfer.regions.list[0]; + if (!region) return (false); + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + var copybuffer = AudioUtils.Copy ( + start, + end + ); + + return (copybuffer); + }; + + this.PlayBuff = function ( buff_arr, chans, sample_rate, aud_cont ) { + var audio_ctx; + + if (aud_cont) audio_ctx = aud_cont; + else audio_ctx = new (w.AudioContext || w.webkitAudioContext)(); + + if (!audio_ctx) return ; + + var bytes = buff_arr[0].byteLength / 4; + + var buffer = audio_ctx.createBuffer ( + chans, + bytes, + sample_rate + ); + + for (var i = 0; i < chans; ++i) { + buffer.getChannelData ( i ).set ( + new Float32Array (buff_arr[ i ]) + ); + } + + var source = audio_ctx.createBufferSource (); + source.buffer = buffer; + + source.connect ( audio_ctx.destination ); + source.start ( 0 ); + + return (source); + }; + + this.GetFX = function ( fx, val ) { + return AudioUtils.FXBank[fx]( val ); + }; + + this.GetWave = function ( buffer, ww, hh, offset, llen, cnv, cx ) { + var chan_data = buffer.getChannelData ( 0 ); + var sample_rate = buffer.sampleRate; + + var peaks = []; + var curr_time = 0; + var width = ww || 200; + var height = hh || 80; + var half_height = (height / 2); + var new_width = width; + var pixels = 0; + var raw_pixels = 0; + + var start_offset = offset || 0; + var end_offset = llen || ((buffer.duration * sample_rate) >> 0); + var length = end_offset - start_offset; + var mod = (length / width) >> 0; + + var max = 0; + var min = 0; + + for (var i = 0; i < new_width; ++i) { + var new_offset = start_offset + (mod * i); + + max = 0; + min = 0; + + if (new_offset >= 0) + { + for (var j = 0; j < mod; j += 3) { + if ( chan_data[ new_offset + j] > max ) { + max = chan_data[ new_offset + j]; + } + else if ( chan_data[ new_offset + j] < min ) { + min = chan_data[ new_offset + j]; + } + } + } + + peaks[2 * i] = max; + peaks[2 * i + 1 ] = min; + } + + var canvas = cnv; + var ctx = cx; + + if (!canvas) { + canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + + ctx = canvas.getContext ('2d', {alpha:false,antialias:false}); + } + + ctx.fillStyle = "#000"; + ctx.fillRect ( 0, 0, width, height ); + ctx.fillStyle = '#99c2c6'; + + ctx.beginPath (); + ctx.moveTo ( 0, half_height ); + + for (var i = 0; i < width; ++i) { + var peak = peaks[i * 2]; + var _h = Math.round (peak * half_height); + ctx.lineTo ( i, half_height - _h); + } + + for (var i = width - 1; i >= 0; --i) { + var peak = peaks[ (i * 2) + 1]; + var _h = Math.round (peak * half_height); + ctx.lineTo ( i, half_height - _h); + } + + ctx.closePath(); + ctx.fill(); + + return (canvas.toDataURL('image/jpeg', 0.56)); + // --- + }; + + app.listenFor ('RequestActionCut', function ( use_clipboard ) { + if (!q.is_ready) return ; + + var region = wavesurfer.regions.list[0]; + if (!region) return (false); + + app.fireEvent ('RequestPause'); + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ( (region.end - region.start), 3) + + app.fireEvent ('StateRequestPush', { + desc : use_clipboard ? 'Cut' : 'Delete', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + + var cutbuffer = AudioUtils.Trim ( + start, + end + ); + wavesurfer.regions.clear(); + + var tmp = (start - 0.03); + if (tmp < 0) tmp = 0; + + app.fireEvent ('RequestSeekTo', tmp / wavesurfer.getDuration ()); + + if (use_clipboard) { + copy_buffer = cutbuffer; + + app.fireEvent ('DidSetClipboard', 1); + app.fireEvent ('DidCut', cutbuffer); + + OneUp ('Cut :: ' + q.TrimTo (start, 2) + ' to ' + q.TrimTo (start/1 + end/1, 2), 1100); + } + else { + OneUp ('Delete :: ' + q.TrimTo (start, 2) + ' to ' + q.TrimTo (start/1 + end/1, 2), 1100); + } + + /* + var image = app.engine.GetWave (copy_buffer); + var eel = document.getElementsByClassName('pk_tb')[0]; + var imm = new Image(); + imm.src = image; + eel.appendChild( imm ); + */ + }); + + app.listenFor ('RequestActionCopy', function () { + if (!q.is_ready) return ; + + var region = wavesurfer.regions.list[0]; + if (!region) return (false); + + app.fireEvent('RequestPause'); + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + var copybuffer = AudioUtils.Copy ( + start, + end + ); + + copy_buffer = copybuffer; + app.fireEvent ('DidSetClipboard', 1); + app.fireEvent ('DidCopy', copybuffer); + + OneUp ('Copied range'); + }); + + app.listenFor ('RequestActionSilence', function ( offset, silence_duration ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + if (!silence_duration || silence_duration < 0) silence_duration = 1; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Silence', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + var start = offset; + var end = silence_duration; + + handleStateInline ( start, end ); + dims = AudioUtils.Insert ( + offset, + AudioUtils.MakeSilence ( silence_duration ) + ); + + // add a region where the paste happened + wavesurfer.regions.clear(); + wavesurfer.regions.add({ + start:dims[0], + end:dims[1], + id:'t' + }); + + app.fireEvent ('RequestSeekTo', (dims[0]/wavesurfer.getDuration())); + + OneUp ('Inserted Silence'); + }); + + app.listenFor ('RequestActionPaste', function () { + if (!q.is_ready) return ; + if (!copy_buffer) return (false); + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Paste', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + var offset = q.TrimTo (wavesurfer.getCurrentTime(), 3); + + handleStateInline ( offset ); + dims = AudioUtils.Insert ( offset, copy_buffer ); + } + else { + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + + dims = AudioUtils.Replace ( + start, + end, + copy_buffer + ); + } + + // add a region where the paste happened + wavesurfer.regions.clear(); + wavesurfer.regions.add({ + start:dims[0], + end:dims[1], + id:'t' + }); + + var new_seek = 0; + if (wavesurfer.getDuration () > 0.0001) { + new_seek = dims[0]/wavesurfer.getDuration (); + } + app.fireEvent ('RequestSeekTo', new_seek); + + OneUp ('Paste to ' + dims[0].toFixed(2), 982); + }); + + var _sk = false; + app.listenFor ('RequestActionRecordToggle', function () { + if (!q.is_ready) { + // if not ready then bring up the new recording toggle! + app.fireEvent('RequestActionNewRec'); + + return ; + } + + if (app.rec.isActive ()) { + app.fireEvent('RequestActionRecordStop'); + } else { + // skipping the sounds of keyboard + if (_sk) return ; + + _sk = true; + setTimeout(function () { + app.fireEvent('RequestActionRecordStart'); + setTimeout(function() { + _sk = false; + }, 50); + },26); + } + }); + + app.listenFor ('RequestActionRecordStop', function () { + if (!q.is_ready) return ; + if (!app.rec.isActive ()) return (false); + + app.rec.stop (); + }); + + app.listenFor ('RequestActionRecordStart', function () { + if (!q.is_ready) return ; + + app.fireEvent ('RequestPause'); + + if (app.rec.isActive ()) return (false); + + var pos = wavesurfer.getCurrentTime () * wavesurfer.backend.buffer.sampleRate; + app.rec.start ( pos, function ( offset, buffers ) { + + // app.fireEvent ('RequestPause'); + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Record Audio', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + // fire did record event! + app.fireEvent ('DidActionRecordStop', !!buffers); + if (!buffers) + { + return ; + } + + handleStateInline ( offset ); + var dims = AudioUtils.ReplaceFloatArrays ( offset, buffers ); + + // add a region where the paste happened + wavesurfer.regions.clear(); + wavesurfer.regions.add({ + start:dims[0], + end:dims[1], + id:'t' + }); + + app.fireEvent ('RequestSeekTo', (dims[0]/wavesurfer.getDuration())); + OneUp ('Recorded Audio ' + dims[0].toFixed(2), 982); + }, function () { + // on start + app.fireEvent ('DidActionRecordStart'); + }); + + // --- ending offset is song full duration... + // if we have a selected area - mark that one as the end + var region = wavesurfer.regions.list[0]; + if (region) + app.rec.setEndingOffset ( region.end * wavesurfer.backend.buffer.sampleRate ); + else + app.rec.setEndingOffset ( wavesurfer.getDuration () * wavesurfer.backend.buffer.sampleRate ); + }); + + app.listenFor ('RequestActionFX_PREVIEW_HardLimit', function ( val ) { + if (!q.is_ready) return ; + if (AudioUtils.previewing) { + AudioUtils.FXPreviewStop (); + app.fireEvent ('DidStopPreview'); + return ; + } + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + AudioUtils.FXPreview( start, end, AudioUtils.FXBank.HardLimit ( val ) ); + app.fireEvent ('DidStartPreview'); + }); + app.listenFor ('RequestActionFX_HardLimit', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Apply Hard Limit (fx)', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + AudioUtils.FX( start, end, AudioUtils.FXBank.HardLimit ( val ) ); + + OneUp ('Applied Hard Limit (fx)'); + }); + + app.listenFor ('RequestActionFX_PARAMEQ', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Apply Parametric EQ (fx)', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + AudioUtils.FX( start, end, AudioUtils.FXBank.ParametricEQ ( val ) ); + + OneUp ('Applied Parametric EQ (fx)'); + }); + app.listenFor ('RequestActionFX_PREVIEW_PARAMEQ', function ( val ) { + if (!q.is_ready || !val) return ; + if (AudioUtils.previewing) { + AudioUtils.FXPreviewStop (); + app.fireEvent ('DidStopPreview'); + return ; + } + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + AudioUtils.FXPreview( start, end, AudioUtils.FXBank.ParametricEQ ( val ) ); + app.fireEvent ('DidStartPreview'); + }); + + app.listenFor ('RequestActionFX_PREVIEW_DISTORT', function ( val ) { + if (!q.is_ready) return ; + if (AudioUtils.previewing) { + AudioUtils.FXPreviewStop (); + app.fireEvent ('DidStopPreview'); + return ; + } + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + AudioUtils.FXPreview( start, end, AudioUtils.FXBank.Distortion ( val ) ); + app.fireEvent ('DidStartPreview'); + }); + app.listenFor ('RequestActionFX_DISTORT', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Apply Distortion (fx)', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + AudioUtils.FX( start, end, AudioUtils.FXBank.Distortion ( val ) ); + + OneUp ('Applied Distortion (fx)'); + }); + + app.listenFor ('RequestActionFX_PREVIEW_DELAY', function ( val ) { + if (!q.is_ready) return ; + if (AudioUtils.previewing) { + AudioUtils.FXPreviewStop (); + app.fireEvent ('DidStopPreview'); + return ; + } + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + AudioUtils.FXPreview( start, end, AudioUtils.FXBank.Delay ( val ) ); + app.fireEvent ('DidStartPreview'); + }); + app.listenFor ('RequestActionFX_DELAY', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Apply Delay (fx)', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + AudioUtils.FX( start, end, AudioUtils.FXBank.Delay ( val ) ); + + OneUp ('Applied Delay (fx)'); + }); + + app.listenFor ('RequestActionFX_PREVIEW_REVERB', function ( val ) { + if (!q.is_ready) return ; + if (AudioUtils.previewing) { + AudioUtils.FXPreviewStop (); + app.fireEvent ('DidStopPreview'); + return ; + } + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + AudioUtils.FXPreview( start, end, AudioUtils.FXBank.Reverb ( val ) ); + app.fireEvent ('DidStartPreview'); + }); + app.listenFor ('RequestActionFX_REVERB', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Apply Reverb (fx)', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + AudioUtils.FX( start, end, AudioUtils.FXBank.Reverb ( val ) ); + + OneUp ('Applied Reverb (fx)'); + }); + + app.listenFor ('RequestActionFX_PREVIEW_COMPRESSOR', function ( val ) { + if (!q.is_ready) return ; + if (AudioUtils.previewing) { + AudioUtils.FXPreviewStop (); + app.fireEvent ('DidStopPreview'); + return ; + } + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + AudioUtils.FXPreview( start, end, AudioUtils.FXBank.Compressor ( val ) ); + app.fireEvent ('DidStartPreview'); + }); + + app.listenFor ('RequestActionFX_Compressor', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Apply Compressor (fx)', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + AudioUtils.FX( start, end, AudioUtils.FXBank.Compressor ( val ) ); + + OneUp ('Applied Compressor (fx)'); + }); + app.listenFor ('RequestActionFX_Normalize', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Normalize ', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3) + var end = q.TrimTo ((region.end - region.start), 3) + + handleStateInline ( start, end ); + AudioUtils.FX( start, end, AudioUtils.FXBank.Normalize ( val ) ); + + OneUp ('Applied Normalize'); + }); + + app.listenFor ('RequestActionFX_Invert', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Invert ', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3) + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + AudioUtils.FX( start, end, AudioUtils.FXBank.Invert() ); + + OneUp ('Applied Invert'); + }); + + app.listenFor ('RequestActionFX_RemSil', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Remove Silence ', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3) + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + + var originalBuffer = wavesurfer.backend.buffer; + var sil_arr = []; + var sil_offset = 210; + var vol_offset = 56; + var count = 0; + var inv_count = 0; + var start = 0; + var end = 0; + var found = false; + var jump = 500; + + for (var i = 0; i < 1; ++i) + { + var channel = originalBuffer.getChannelData (i); + + for (var j = 0; j < channel.length; ++j) + { + if (Math.abs (channel[j]) < 0.000368) + { + if (count === 0) { + + if (j > jump) + start = j - jump; + else + start = j; + } + if (++count > sil_offset) + { + inv_count = 0; + end = j; + found = true; + } + } + else + { + if (found) + { + if (++inv_count > vol_offset) + { + sil_arr.push([start, end]); + j += jump; + + count = 0; + start = 0; + end = 0; + found = false; + inv_count = 0; + } + else + { + end = j; + } + } + else + { + count = 0; + start = 0; + end = 0; + found = false; + inv_count = 0; + } + } + } + + if (found) { + sil_arr.push([start, end]); + } + } + + if (sil_arr.length > 0) + { + var reduce = 0; + for (var i = 0; i < sil_arr.length; ++i) + { + reduce += (sil_arr[i][1] - sil_arr[i][0]); + } + + var emptySegment = wavesurfer.backend.ac.createBuffer ( + originalBuffer.numberOfChannels, + originalBuffer.length - reduce, + originalBuffer.sampleRate + ); + + for (var i = 0; i < originalBuffer.numberOfChannels; ++i) + { + var channel = originalBuffer.getChannelData ( i ); + var new_channel = emptySegment.getChannelData ( i ); + + var sil_offset = 0; + var o = 0; + var sil_curr = sil_arr[o]; + var sil_curr_start = sil_curr[0]; + var sil_curr_end = sil_curr[1]; + var h = 0; + var use_old = false; + var old_h = 0; + + for (var j = 0; j < new_channel.length; ++j) + { + h = j + sil_offset; + if (h > sil_curr_start && h < sil_curr_end) + { + if (h < sil_curr_start + jump) + { + var perc = (jump - (h - sil_curr_start)) / jump; + new_channel[ j ] = (channel[ h ] * perc) ; // / (h - sil_curr_start)); + new_channel[ j ] += (1 - perc) * channel[ j + (sil_offset + (sil_curr_end - sil_curr_start)) ]; + + continue; + } + else + { + sil_offset = sil_offset + (sil_curr_end - sil_curr_start); + sil_curr = sil_arr[++o]; + if (sil_curr) + { + sil_curr_start = sil_curr[0]; + sil_curr_end = sil_curr[1]; + } + h = j + sil_offset; + } + } + + new_channel[ j ] = channel[ h ]; + } + } + + AudioUtils.FullReplace ( + emptySegment + ); + } + + setTimeout (function() { + wavesurfer.drawBuffer(); + },40); + + OneUp ('Applied :: Remove Silence'); + }); + + + var _compute_channels = function () { + var buff = wavesurfer.backend.buffer; + var chans = buff.numberOfChannels; + + if (chans === 1) { + wavesurfer.ActiveChannels = [1]; + app.el.classList.add ('pk_mono'); + } + else { + wavesurfer.ActiveChannels = [1, 1]; + app.el.classList.remove ('pk_mono'); + } + + wavesurfer.drawer.params.ActiveChannels = wavesurfer.ActiveChannels; + wavesurfer.SelectedChannelsLen = chans; + }; + + app.listenFor ('RequestActionFX_Flip', function ( val, val2 ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var start = 0; + var end = wavesurfer.getDuration(); + + function handleStateInline ( start, end, title, cb ) { + app.fireEvent ('StateRequestPush', { + desc : title, + meta : [ start, end ], + data : wavesurfer.backend.buffer, + cb : cb + }); + } + + if (val === 'flip') + { + handleStateInline ( start, end, 'Flip Channels' ); + AudioUtils.FX ( start, end, AudioUtils.FXBank.Flip ( val ) ); + } + else if (val === 'stereo') + { + handleStateInline ( start, end, 'Make Stereo', function(){_compute_channels ()}); + + var originalBuffer = wavesurfer.backend.buffer; + var emptySegment = wavesurfer.backend.ac.createBuffer ( + 2, + originalBuffer.length, + originalBuffer.sampleRate + ); + emptySegment.getChannelData ( 0 ).set ( + originalBuffer.getChannelData ( 0 ) + ); + emptySegment.getChannelData ( 1 ).set ( + originalBuffer.getChannelData ( 0 ) + ); + + AudioUtils.FullReplace ( + emptySegment + ); + + wavesurfer.regions.clear(); + wavesurfer.regions.add({ + start:start, + end:end, + id:'t' + }); + + _compute_channels (); + + app.fireEvent ('RequestSeekTo', 0.00); + } + else if (val === 'mono') + { + handleStateInline ( start, end, 'Make Mono', function(){_compute_channels()} ); + + var originalBuffer = wavesurfer.backend.buffer; + var emptySegment = wavesurfer.backend.ac.createBuffer ( + 1, + originalBuffer.length, + originalBuffer.sampleRate + ); + emptySegment.getChannelData ( 0 ).set ( + originalBuffer.getChannelData ( val2 ) + ); + AudioUtils.FullReplace ( + emptySegment + ); + + wavesurfer.regions.clear(); + wavesurfer.regions.add({ + start:start, + end:end, + id:'t' + }); + + _compute_channels (); + + app.fireEvent ('RequestSeekTo', 0.00); + } + + OneUp ('Applied Channel Change: ' + val); + }); + + app.listenFor ('RequestActionFX_Reverse', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Reverse ', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3) + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + AudioUtils.FX( start, end, AudioUtils.FXBank.Reverse() ); + + OneUp ('Applied Reverse'); + }); + + var noisernn_load = !1; + app.listenFor("RequestActionFX_NoiseRNN", function (a) { + var h = wavesurfer; + if (q.is_ready) { // n -> q + app.fireEvent("RequestPause"); + var b = function () { + var f = h.regions.list[0]; + f || (h.regions.add({ start: 0, end: h.getDuration() - 0, id: "t" }), (f = h.regions.list[0])); + var m = q.TrimTo(f.start, 3), + k = q.TrimTo(f.end - f.start, 3); + f = f.end - f.start; + f = q.TrimTo(f, 3); + app.fireEvent("StateRequestPush", { desc: "Apply Noise RNN (fx)", meta: [m, k], data: h.backend.buffer }); + for (var u = AudioUtils.Copy(m, k), w = 0; w < u.numberOfChannels; w++) { + var x = u.getChannelData(w), + z = wasm_denoise_stream_perf(x); + x.set(z); + } + AudioUtils.Replace(m, k, u); + app.fireEvent("RequestSeekTo", m / h.getDuration()); + wavesurfer.regions.clear(); + h.regions.add({ start: m, end: m + f, id: "t" }); + OneUp("Applied Noise RNN (fx)"); + }; + noisernn_load + ? b() + : ((a = document.createElement("script")), + (a.src = "rnn_denoise.js"), + (a.onload = function () { + noisernn_load = !0; + var f = function () { + window.Module && window.Module.asm && window.Module.asm.malloc + ? b() + : setTimeout(function () { + f(); + }, 350); + }; + setTimeout(function () { + f(); + }, 100); + }), + (a.onerror = function () { + alert("Could not download noise Reduction script"); + }), + document.head.appendChild(a)); + } + }); + + app.listenFor ('RequestActionFX_FadeIn', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Apply Fade In (fx)', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + AudioUtils.FX( start, end, AudioUtils.FXBank.FadeIn() ); + + OneUp ('Applied Fade In (fx)'); + }); + app.listenFor ('RequestActionFX_FadeOut', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Apply Fade Out (fx)', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + AudioUtils.FX( start, end, AudioUtils.FXBank.FadeOut() ); + + OneUp ('Applied Fade Out (fx)'); + }); + + + var fx_preview_debounce = null; + app.listenFor ('RequestActionFX_UPDATE_PREVIEW', function ( val ) { + if (!AudioUtils.previewing) return ; + + clearTimeout (fx_preview_debounce); + fx_preview_debounce = setTimeout(function () { + AudioUtils.FXPreviewUpdate ( val ); + }, 44); + }); + app.listenFor ('RequestActionFX_TOGGLE', function ( val ) { + + if (val) + { + AudioUtils.FXPreviewInit (true); + return ; + } + + app.fireEvent ('DidTogglePreview', AudioUtils.FXPreviewToggle ()); + }); + app.listenFor ('RequestActionFX_PREVIEW_STOP', function () { + AudioUtils.FXPreviewStop (); + app.fireEvent ('DidStopPreview'); + }); + app.listenFor ('RequestActionFX_PREVIEW_GAIN', function ( val ) { + if (!q.is_ready) return ; + if (AudioUtils.previewing) { + AudioUtils.FXPreviewStop (); + app.fireEvent ('DidStopPreview'); + return ; + } + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + AudioUtils.FXPreview( start, end, AudioUtils.FXBank.Gain( val ) ); + + app.fireEvent ('DidStartPreview'); + }); + + app.listenFor ('RequestActionFX_GAIN', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Apply Gain (fx)', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + handleStateInline ( start, end ); + AudioUtils.FX( start, end, AudioUtils.FXBank.Gain( val ) ); + + OneUp ('Applied Gain (fx)'); + }); + + app.listenFor ('RequestActionFX_PREVIEW_SPEED', function ( val ) { + if (!q.is_ready) return ; + if (AudioUtils.previewing) { + AudioUtils.FXPreviewStop (); + app.fireEvent ('DidStopPreview'); + return ; + } + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + + AudioUtils.FXPreview( start, end, AudioUtils.FXBank.Speed( val ) ); + + app.fireEvent ('DidStartPreview'); + }); + + app.listenFor ('RequestActionFX_RATE', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Apply Rate (fx)', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + var duration = (region.end - region.start) / val; + duration = q.TrimTo (duration, 3); + + handleStateInline ( start, end ); + + var fx_buffer = AudioUtils.Copy ( start, end ); + var originalBuffer = wavesurfer.backend.buffer; + var new_offset = ((start/1) * originalBuffer.sampleRate) >> 0; + var new_len = ((duration/1) * originalBuffer.sampleRate) >> 0; + var old_len = ((end/1) * originalBuffer.sampleRate) >> 0; + var stretch_ratio = new_len / old_len; + + var getOfflineAudioContext = function (channels, sampleRate, duration) { + return new (window.OfflineAudioContext || + window.webkitOfflineAudioContext)(channels, duration, sampleRate); + }; + var audio_ctx = getOfflineAudioContext ( // offlineCtx + wavesurfer.SelectedChannelsLen, // orig_buffer.numberOfChannels, + fx_buffer.sampleRate, + new_len + ); + + /* + var TimeStretcher = function(o){o=o||{};this.ws=o.windowSize||1024;this.or=o.overlapRatio||0.5;this.sw=o.seekWindowMs||30;} + TimeStretcher.prototype.stretch=function(buf,ts){ + if(ts<=0) throw new Error("Stretch ratio must be positive"); + var ch=buf.numberOfChannels, sr=buf.sampleRate, il=buf.length, ol=Math.floor(il*ts), + out=new AudioBuffer({numberOfChannels:ch,length:ol,sampleRate:sr}); + for(var c=0;c0 && Math.abs(nIdx-iIdx)>hs){ + var ssi=Math.max(0,nIdx-sw), sei=Math.min(il-ws,nIdx+sw); + iIdx=this._findBestMatch(inD,iIdx+hs,ssi,sei,ws); + } else { iIdx=nIdx; } + for(var i=0;i1){var g=0.95/m; for(var i=0;i 1 + if (stretchRatio > 1) { + grainDurationSec = synthesisHopSec / (1 - desiredOverlap); + } + + // Convert durations to samples + const grainSize = Math.floor(grainDurationSec * sampleRate); + const analysisHop = Math.floor(analysisHopSec * sampleRate); + const synthesisHop = Math.floor(synthesisHopSec * sampleRate); + + // Precompute Hann window + const window = new Float32Array(grainSize); + for (let i = 0; i < grainSize; i++) { + // Using (grainSize - 1) so that the window spans [0, grainDurationSec] + window[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / (grainSize - 1))); + } + + // Estimate number of grains and output length + const numGrains = Math.floor((samples[0].length - grainSize) / analysisHop); + const outputLength = synthesisHop * numGrains + grainSize; + let output = [ new Float32Array(outputLength) ]; + for (let i = 1; i < channels_len; ++i) { + output.push ( new Float32Array(outputLength) ); + } + + // Process each grain: copy, window, and add to output + let inputIndex = 0; + let outputIndex = 0; + for (let n = 0; n < numGrains; ++n) { + // For each sample in the grain, multiply by the window and add to the output + for (let i = 0; i < grainSize; ++i) { + for (let j = 0; j < channels_len; ++j) { + output[j][outputIndex + i] += samples[j][inputIndex + i] * window[i]; + } + } + inputIndex += analysisHop; + outputIndex += synthesisHop; + } + + /* + let normalization = new Float32Array(outputLength); + inputIndex = 0; + outputIndex = 0; + for (let n = 0; n < numGrains; ++n) { + for (let i = 0; i < grainSize; ++i) { + normalization[outputIndex + i] += window[i]; + } + inputIndex += analysisHop; + outputIndex += synthesisHop; + } + + // Normalize each channel's output: + for (let j = 0; j < channels_len; ++j) { + for (let i = 0; i < outputLength; ++i) { + if (normalization[i] > 0) { + output[j][i] /= normalization[i]; + } + } + } + */ + + return output; + }; + + /// ----- + var filter = []; + //if (stretch_ratio < 1) { + // var fx = AudioUtils.FXBank.Rate( stretch_ratio ); + // var source = {buffer:null, disconnect:function(){}}; + // source.buffer = fx_buffer; + // filter = fx.filter ( audio_ctx, audio_ctx.destination, source, duration ); + //} + //else + //{ + // use timestretcher here... + // var ts = new TimeStretcher({windowSize:2048,overlapRatio:0.75,seekWindowMs:20}).stretch(fx_buffer,stretch_ratio); + const stretchedSamples = stretchAudio(fx_buffer, fx_buffer.sampleRate, stretch_ratio); + + // Optionally, if you need an AudioBuffer from the stretchedSamples: + // const offlineCtx = new OfflineAudioContext(stretchedSamples.length, stretchedSamples[0].length, fx_buffer.sampleRate); + const newBuffer = audio_ctx.createBuffer(stretchedSamples.length, stretchedSamples[0].length, fx_buffer.sampleRate); + + for (let i = 0; i < stretchedSamples.length; ++i) { + newBuffer.copyToChannel(stretchedSamples[i], i); + } + + var source = audio_ctx.createBufferSource (); + source.buffer = newBuffer; + source.connect ( audio_ctx.destination ); + source.start (); + //} + + q.in_fx = true; + app.ui.InteractionHandler.on = true; + // OneUp ('Please wait, applying FX', 2600); + + var offline_callback = function( rendered_buffer ) { + AudioUtils.Replace (start, end, rendered_buffer); + + wavesurfer.regions.clear(); + wavesurfer.regions.add({ + start:start, + end: start + duration, + id:'t' + }); + + app.fireEvent ('RequestSeekTo', (start/wavesurfer.getDuration())); + + OneUp ('Applied Rate (fx)'); + + if (filter.length > 0) { + for (var i = 0; i < filter.length; ++i) filter[i].disconnect (); + } else filter && filter.disconnect && filter.disconnect (); + + rendered_buffer = fx_buffer = filter = null; + source.disconnect (); + + q.in_fx = false; + app.ui.InteractionHandler.on = false; + }; + + var offline_renderer = audio_ctx.startRendering(); + if (offline_renderer) + offline_renderer.then( offline_callback ).catch(function(err) { + console.log('Rendering failed: ' + err); + }); + else + audio_ctx.oncomplete = function ( e ) { + offline_callback ( e.renderedBuffer ); + }; + }); + + app.listenFor ('RequestActionFX_PREVIEW_RATE', function ( val ) { + if (!q.is_ready) return ; + if (AudioUtils.previewing) { + AudioUtils.FXPreviewStop (); + app.fireEvent ('DidStopPreview'); + return ; + } + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + var duration = (region.end - region.start) / val; + + var originalBuffer = wavesurfer.backend.buffer; + var new_offset = ((start/1) * originalBuffer.sampleRate) >> 0; + var new_len = ((duration/1) * originalBuffer.sampleRate) >> 0; + var old_len = ((end/1) * originalBuffer.sampleRate) >> 0; + + // ----- + var stretch_ratio = new_len / old_len; + + AudioUtils.FXPreview( start, end, AudioUtils.FXBank.Rate( stretch_ratio ) ); + + app.fireEvent ('DidStartPreview'); + }); + + app.listenFor ('RequestActionFX_SPEED', function ( val ) { + if (!q.is_ready) return ; + + app.fireEvent('RequestPause'); + + var region = wavesurfer.regions.list[0]; + var dims = [ 0, 0 ]; + + function handleStateInline ( start, end ) { + app.fireEvent ('StateRequestPush', { + desc : 'Apply Speed (fx)', + meta : [ start, end ], + data : wavesurfer.backend.buffer + }); + } + + if (!region) { + wavesurfer.regions.add({ + start:0.00, + end:wavesurfer.getDuration() - 0.00, + id:'t' + }); + region = wavesurfer.regions.list[0]; + } + + + var start = q.TrimTo (region.start, 3); + var end = q.TrimTo ((region.end - region.start), 3); + var duration = (region.end - region.start) / val; + duration = q.TrimTo (duration, 3); + + handleStateInline ( start, end ); + + var fx_buffer = AudioUtils.Copy ( start, end ); + var originalBuffer = wavesurfer.backend.buffer; + var new_offset = ((start/1) * originalBuffer.sampleRate) >> 0; + var new_len = ((duration/1) * originalBuffer.sampleRate) >> 0; + var old_len = ((end/1) * originalBuffer.sampleRate) >> 0; + + /* + var emptySegment = wavesurfer.backend.ac.createBuffer ( + wavesurfer.SelectedChannelsLen, + new_len, + originalBuffer.sampleRate + );*/ + + q.in_fx = true; + app.ui.InteractionHandler.on = true; + var fx = AudioUtils.FXBank.Speed( val ); + + var getOfflineAudioContext = function (channels, sampleRate, duration) { + return new (window.OfflineAudioContext || + window.webkitOfflineAudioContext)(channels, duration, sampleRate); + }; + var audio_ctx = getOfflineAudioContext ( + wavesurfer.SelectedChannelsLen, // orig_buffer.numberOfChannels, + originalBuffer.sampleRate, + new_len + ); + + var source = audio_ctx.createBufferSource (); + source.buffer = fx_buffer; + + var filter = fx.filter ( audio_ctx, audio_ctx.destination, source, duration ); + + source.start (); + + var offline_callback = function( rendered_buffer ) { + + AudioUtils.Replace (start, end, rendered_buffer); + + wavesurfer.regions.clear(); + wavesurfer.regions.add({ + start:start, + end: start + duration, + id:'t' + }); + + app.fireEvent ('RequestSeekTo', (start/wavesurfer.getDuration())); + + OneUp ('Applied Speed (fx)'); + + if (filter.length > 0) { + for (var i = 0; i < filter.length; ++i) filter[i].disconnect (); + } else filter && filter.disconnect && filter.disconnect (); + + // is this needed? + rendered_buffer = fx_buffer = filter = null; + source.disconnect (); + // audio_ctx.close (); + // - + q.in_fx = false; + app.ui.InteractionHandler.on = false; + }; + + var offline_renderer = audio_ctx.startRendering(); + if (offline_renderer) + offline_renderer.then( offline_callback ).catch(function(err) { + console.log('Rendering failed: ' + err); + }); + else + audio_ctx.oncomplete = function ( e ) { + offline_callback ( e.renderedBuffer ); + }; + }); + + app.listenFor ('StateDidPop', function ( state, undo ) { + if (!q.is_ready) return ; + app.fireEvent ('RequestPause'); + + wavesurfer.regions.clear(); + wavesurfer.loadDecodedBuffer (state.data); + + if (state.cb) state.cb (); + + var new_durr = wavesurfer.getDuration (); + app.fireEvent ('DidUpdateLen', new_durr); + + if (state.meta && state.meta.length > 0) + { + if (state.meta[1]) + { + wavesurfer.regions.add({ + start:state.meta[0]/1, + end:state.meta[0]/1 + state.meta[1]/1, + id:'t' + }); + } + else + { + if (!new_durr) new_durr = 0.0001; + app.fireEvent ('RequestSeekTo', (state.meta[0]/new_durr)); + } + } + + if (undo) OneUp ('Undo ' + state.desc); + else OneUp ('Redo ' + state.desc); + }); + + + // --- + app.listenFor ('RequestChanToggle', function ( chan_index, force_val ) { + if (!q.is_ready) return (false); + + if (wavesurfer.ActiveChannels.length <= chan_index) return (false); + + var oldval = wavesurfer.ActiveChannels[ chan_index ]; + var val = -1; + + if (force_val) val = force_val; + else { + if (oldval === 1) val = 0; + else val = 1; + } + + if (oldval !== val) + { + wavesurfer.ActiveChannels[ chan_index ] = val; + if (val === 0) { + --wavesurfer.SelectedChannelsLen; + // silece the channel itself + + if (chan_index === 0) { + wavesurfer.backend.gainNode2.gain.value = 0.0; + } else { + wavesurfer.backend.gainNode1.gain.value = 0.0; + } + } + else { + ++wavesurfer.SelectedChannelsLen; + + if (chan_index === 0) { + wavesurfer.backend.gainNode2.gain.value = 1.0; + } else { + wavesurfer.backend.gainNode1.gain.value = 1.0; + } + } + + wavesurfer.ForceDraw (); + app.fireEvent ('DidChanToggle', chan_index, val); + } + }); + + // ---- + wavesurfer.on( 'region-updated', function () { + if (wavesurfer.regions.list[0]) + { + app.fireEvent ('DidCreateRegion', wavesurfer.regions.list[0]); + } + }); + wavesurfer.on( 'region-update-end', function () { + app.fireEvent ('DidCreateRegion', wavesurfer.regions.list[0]); + + var start = wavesurfer.regions.list[0].start; + if (!wavesurfer.isPlaying ()) + app.fireEvent ('RequestSeekTo', (start/wavesurfer.getDuration() )); + }); + wavesurfer.on( 'cursorcenter', function ( e ) { + app.fireEvent ('DidCursorCenter', e, wavesurfer.ZoomFactor); + }); + + var wave = wavesurfer.drawer.canvases[0].wave.parentNode; + + var drag_x = 0; + var drag_move = function ( e ) { + + var diff = drag_x - e.clientX; + + // find diff percentage from full width... + + // drag the waveform now + app.fireEvent ('RequestPan', diff ); + + drag_x = e.clientX; + }; + + app.listenFor ('RequestZoom', function ( diff, mode ) { + var wv = wavesurfer; + + // compute new ZoomFactor... + diff *= wv.ZoomFactor; + + // compute availabel left ZoomFactor + if (mode === -1) + { + var width = wv.drawer.width; + var available_pixels = width - width/wv.ZoomFactor; + var target = wv.ZoomFactor - 1; + if (target <= 0) return ; + + var old_zoomfactor = wv.ZoomFactor; + wv.ZoomFactor += (diff*target)/available_pixels; + if (wv.ZoomFactor < 1) wv.ZoomFactor = 1; + + var new_vis_dur = wv.getDuration() / wv.ZoomFactor; + + if (new_vis_dur <= 0.5) + { + wv.ZoomFactor = old_zoomfactor; + return ; + } + + wv.VisibleDuration = new_vis_dur; + + var time_moved = wv.VisibleDuration * (diff / wv.drawer.width); + wv.LeftProgress += time_moved; + + if (wv.LeftProgress + wv.VisibleDuration >= wv.getDuration ()) + { + wv.LeftProgress = wv.getDuration () - wv.VisibleDuration; + } + else if (wv.LeftProgress < 0) { + wv.LeftProgress = 0; + } + } + else if (mode === 1) + { + var width = wv.drawer.width; + var available_pixels = width - width/wv.ZoomFactor; + var target = wv.ZoomFactor - 1; + if (target <= 0) return ; + + var old_factor = wv.ZoomFactor; + wv.ZoomFactor -= (diff*target)/available_pixels; + if (wv.ZoomFactor < 1) wv.ZoomFactor = 1; + var temp = wv.getDuration() / wv.ZoomFactor; + if (temp + wv.LeftProgress > wv.getDuration()) { + wv.ZoomFactor = old_factor; + } + else + { + if (temp <= 0.5) + { + wv.ZoomFactor = old_factor; + return ; + } + + wv.VisibleDuration = temp; + } + // - + } + + // wv.ZoomFactor -= Math.abs (diff / (wv.drawer.width / 2)); + // console.log( diff + " BLAH " + wv.ZoomFactor + ' ' + (diff / wv.drawer.width) ); + wv.ForceDraw (); + app.fireEvent ('DidZoom', [wavesurfer.ZoomFactor, (wavesurfer.LeftProgress/wavesurfer.getDuration()) * 100, wavesurfer.params.verticalZoom]); + }); + + app.listenFor ('RequestPan', function( diff, mode ) { + var wv = wavesurfer; + + if (mode === 1) diff *= wv.ZoomFactor; + else if (mode === 2) { + var time_moved = wv.getDuration() * (diff / wv.drawer.width); + wv.LeftProgress = time_moved; + + wv.ForceDraw (); + app.fireEvent ('DidZoom', [wavesurfer.ZoomFactor, (wavesurfer.LeftProgress/wavesurfer.getDuration()) * 100, wavesurfer.params.verticalZoom]); + + return ; + } + + if (wv.ZoomFactor > 0) + { + // drag and draw by X pixels... + var time_moved = wv.VisibleDuration * (diff / wv.drawer.width); + wv.LeftProgress += time_moved; + + if (wv.LeftProgress + wv.VisibleDuration >= wv.getDuration ()) + { + wv.LeftProgress = wv.getDuration () - wv.VisibleDuration; + } + else if (wv.LeftProgress < 0) { + wv.LeftProgress = 0; + } + + wv.ForceDraw (); + app.fireEvent ('DidZoom', [wavesurfer.ZoomFactor, (wavesurfer.LeftProgress/wavesurfer.getDuration()) * 100, wavesurfer.params.verticalZoom]); + } + }); + + + wave.addEventListener ('mousedown', function( e ) { + if (e.which === 3) { + e.preventDefault(); + + wavesurfer.Interacting |= (1 << 1); + + drag_x = e.clientX; + wave.className = 'pk_grabbing'; + + document.addEventListener ('mousemove', drag_move, false); + return (false); + } else { + app.fireEvent ('MouseDown'); + app.fireEvent ('RequestChanToggle', 0, 1); + app.fireEvent ('RequestChanToggle', 1, 1); + } + }, false); + wave.addEventListener ('mouseleave', function( e ) { + document.removeEventListener ('mousemove', drag_move); + + if (wave.className !== '') + { + wave.className = ''; + setTimeout(function () { + wavesurfer.Interacting &= ~(1 << 1); + }, 20); + + } + }, false); + wave.addEventListener ('mouseup', function( e ) { + if (e.which === 3) + { + if (wave.className !== '') + { + wave.className = ''; + setTimeout(function () { + wavesurfer.Interacting &= ~(1 << 1); + }, 20); + } + document.removeEventListener ('mousemove', drag_move); + } + }, false); + + app.fireEvent ('RequestResize'); + + app.listenFor ('RequestViewFollowCursorToggle', function () { + var val = !wavesurfer.FollowCursor; + wavesurfer.FollowCursor = val; + + // jump to curr cursor position + if (val && q.is_ready) { + wavesurfer.CursorCenter (); + } + + app.fireEvent ( 'DidViewFollowCursorToggle', val ); + }); + app.listenFor ('RequestViewPeakSeparatorToggle', function () { + if (!q.is_ready) return ; + + var val = !wavesurfer.params.limits ; + wavesurfer.params.limits = val; + + wavesurfer.ForceDraw (); + + app.fireEvent ( 'DidViewPeakSeparatorToggle', val ); + }); + + + app.listenFor ('RequestViewTimelineToggle', function () { + if (!q.is_ready) return ; + + var val = !wavesurfer.params.timeline ; + wavesurfer.params.timeline = val; + + wavesurfer.ForceDraw (); + + app.fireEvent ( 'DidViewTimelineToggle', val ); + }); + + app.listenFor ('RequestViewCenterToCursor', function () { + if (!q.is_ready) return ; + wavesurfer.CursorCenter (); + }); + + + app.listenFor ('RequestZoomUI', function (type, val) { + if (!q.is_ready) return ; + + if (type === 0) { + wavesurfer.ResetZoom (); + return ; + } + + if (type === 'h') { + wavesurfer.SetZoom ( 0.5, val ); + } + + if (type === 'v') { + wavesurfer.SetZoomVertical ( val ); + } + }); + // - + + + this.ID3 = function ( arraybuffer ) { + var tags = null; + // var ttt = window.performance.now(); + + var bytes = new Uint8Array( arraybuffer ); + if (bytes.length < 64) { + app.fireEvent ('RequestActionID3', 1, tags); + return tags; + } + + if (bytes[0] === 73 && bytes[1] === 68 && bytes[2] === 51) { + tags = ID3v2.ReadTags ( arraybuffer ); + + //console.log( window.performance.now() - ttt ); + // console.log( tags ); + } + else if (bytes[4] === 102 && bytes[5] === 116 && bytes[6] === 121 && + bytes[7] === 112 && bytes[8] === 77 && bytes[9] === 52) { + + tags = ID4.ReadTags ( arraybuffer ); + // console.log( window.performance.now() - ttt ); + // console.log( tags ); + } + bytes = null; + + app.fireEvent ('RequestActionID3', 1, tags); + + return (tags); + }; + // --- + }; + + PKAE._deps.engine = PKEng; + +})( window, document, PKAudioEditor ); \ No newline at end of file diff --git a/audiomass-editor/src/eq.html b/audiomass-editor/src/eq.html new file mode 100755 index 0000000..987134f --- /dev/null +++ b/audiomass-editor/src/eq.html @@ -0,0 +1,220 @@ + + + + + AudioMass - Frequency Analysis + + + + + +
FREQUENCY ANALYSER
+ + DOCK INTERFACE + X + + + + + + \ No newline at end of file diff --git a/audiomass-editor/src/flac.js b/audiomass-editor/src/flac.js new file mode 100644 index 0000000..e489c15 --- /dev/null +++ b/audiomass-editor/src/flac.js @@ -0,0 +1,131 @@ +// FLAC worker for encoding audio using libflac.js + +importScripts('libflac.js'); + +var flacEncoder; +var FLAC_INITIALIZED = false; +var sample_rate = 44100; +var compression = 5; // Default compression (0-8) +var channels = 1; +var buffers = []; +var bufIndex = 0; +var first_buffer = true; +var samples_left = null; +var samples_right = null; + +function convert(n) { + var v = n < 0 ? n * 32768 : n * 32767; + return Math.max(-32768, Math.min(32768, v)); +} + +function initFLAC() { + if (FLAC_INITIALIZED) return true; + + // SAMPLERATE, CHANNELS, BPS, COMPRESSION, 0, VERIFY, BLOCK_SIZE); + flacEncoder = Flac.create_libflac_encoder(sample_rate, channels, 16, compression, 0, true, 0); + if (flacEncoder != 0) { + var status = Flac.init_encoder_stream(flacEncoder, function(buffer, bytes) { + buffers.push(new Uint8Array(buffer)); + bufIndex += buffer.byteLength; + }); + + FLAC_INITIALIZED = true; + return status == 0; + } + + return false; +} + +function interleave(inputL, inputR) { + var length = inputL.length + inputR.length; + var result = new Int32Array(length); + + var index = 0, + inputIndex = 0; + + while (index < length) { + result[index++] = inputL[inputIndex]; + result[index++] = inputR[inputIndex]; + ++inputIndex; + } + return result; +} + +onmessage = function(ev) { + if (!ev.data) return; + + if (ev.data.sample_rate) { + sample_rate = ev.data.sample_rate / 1; + compression = ev.data.flac_compression; + channels = ev.data.channels / 1; + + initFLAC(); + return; + } + + if (first_buffer) { + samples_left = new Int16Array(ev.data, 0); + first_buffer = false; + + if (channels > 1) return; + } + + if (ev.data && channels > 1) { + samples_right = new Int16Array(ev.data, 0); + } + + if (!FLAC_INITIALIZED) { + postMessage({percentage: 0}); + return; + } + + // Progress update + postMessage({percentage: 50}); + + // Process the audio data + var interleaved = null; + var samples = null; + + if (channels > 1) { + // Create interleaved buffer for stereo + interleaved = interleave(samples_left, samples_right); + samples = interleaved; + } else { + // Use mono buffer directly + samples = samples_left; + } + + // Encode the audio data + if (channels > 1) { + Flac.FLAC__stream_encoder_process_interleaved(flacEncoder, samples, samples_left.length); + } else { + var tmp_samples = new Int32Array(samples_left.length); + var tmp_index = 0; + while (tmp_index < samples_left.length) { + tmp_samples[tmp_index] = samples_left[tmp_index]; + ++tmp_index; + } + Flac.FLAC__stream_encoder_process(flacEncoder, [tmp_samples], samples_left.length); + } + + // Finish encoding + Flac.FLAC__stream_encoder_finish(flacEncoder); + + // Combine all buffers into a single Uint8Array + var outputData = new Uint8Array(bufIndex); + var offset = 0; + for (var i = 0; i < buffers.length; i++) { + outputData.set(buffers[i], offset); + offset += buffers[i].length; + } + + // Create blob and return + var blob = new Blob([outputData], {type: 'audio/flac'}); + postMessage(blob); + + // Clean up + Flac.FLAC__stream_encoder_delete(flacEncoder); + FLAC_INITIALIZED = false; + buffers = []; + bufIndex = 0; +} \ No newline at end of file diff --git a/audiomass-editor/src/fonts/icomoon.eot b/audiomass-editor/src/fonts/icomoon.eot new file mode 100755 index 0000000..92dc0bf Binary files /dev/null and b/audiomass-editor/src/fonts/icomoon.eot differ diff --git a/audiomass-editor/src/fonts/icomoon.svg b/audiomass-editor/src/fonts/icomoon.svg new file mode 100755 index 0000000..759b460 --- /dev/null +++ b/audiomass-editor/src/fonts/icomoon.svg @@ -0,0 +1,26 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/audiomass-editor/src/fonts/icomoon.ttf b/audiomass-editor/src/fonts/icomoon.ttf new file mode 100755 index 0000000..1a8b27a Binary files /dev/null and b/audiomass-editor/src/fonts/icomoon.ttf differ diff --git a/audiomass-editor/src/fonts/icomoon.woff b/audiomass-editor/src/fonts/icomoon.woff new file mode 100755 index 0000000..e53026a Binary files /dev/null and b/audiomass-editor/src/fonts/icomoon.woff differ diff --git a/audiomass-editor/src/fx-auto.js b/audiomass-editor/src/fx-auto.js new file mode 100644 index 0000000..a4fbece --- /dev/null +++ b/audiomass-editor/src/fx-auto.js @@ -0,0 +1,457 @@ +(function ( w, d, PKAE ) { + 'use strict'; + + var _pid = 0; + var _aid = 0; + + function FXAutomation ( app, filter_modal, val_cb, preview_cb ) { + var q = this; + + q.modal = filter_modal; + q.app = app; + q.wv = app.engine.wavesurfer; + q.points = {}; + q.act = null; + q.act_point = null; + q.in_auto = false; + q.rbuff = null; + + q.btn_auto = _make_btn_auto ( q ); + + q.GetValue = function () { + var data = []; + + var inputs = q.modal.el_body.getElementsByTagName('input'); + var plen = q.points.length; + + for (var i = 0; i < inputs.length; ++i) + { + var curr = inputs[i]; + if (q.points[curr.id]) + { + var arr = []; + var p = q.points[curr.id]; + for (var j = 0; j < p.length; ++j) + { + var tmp = { + time: p[j].time, + val: p[j].val + }; + arr.push(tmp); + val_cb && val_cb (tmp, curr); + } + data.push (arr); + } + else + { + var tmp = { + val: curr.value + }; + + data.push (tmp); + val_cb && val_cb (tmp, curr); + } + } + + return (data); + }; + + q.cw = 500; + q.ch = 200; + var els = _make_canvas ( q, q.cw, q.ch ); + q.canvas = els[0]; + q.ctx = els[1]; + + + var _fillstyle = '#d9d955'; + q.Render = function () { + var ctx = q.ctx; + var cw = q.cw; + var ch = q.ch; + + if (q.rbuff) + q.app.engine.GetWave (q.rbuff, 500, 200, null, null, q.canvas, q.ctx); + + // ctx.clearRect (0, 0, q.cw, q.ch); + ctx.fillStyle = _fillstyle; + ctx.strokeStyle = '#FF0000'; + + if (!q.act) return ; + + ctx.beginPath (); + ctx.moveTo ( 0, ch / 2 ); + var last_y = ch / 2; + + for (var o = 0; o < q.points[q.act.id].length; ++o) + { + var curr = q.points[q.act.id][ o ]; + + var center_x = curr.ax; + var center_y = curr.ay; + + ctx.lineTo ( center_x, center_y ); + last_y = center_y; + } + + ctx.lineTo ( cw, last_y ); + ctx.stroke (); + + var radius = 6; + for (var o = 0; o < q.points[q.act.id].length; ++o) + { + var curr = q.points[q.act.id][ o ]; + + var center_x = curr.ax; + var center_y = curr.ay; + + ctx.beginPath (); + ctx.arc (center_x, center_y, radius, 0, 2 * Math.PI, false); + + if (curr === q.act_point) { + ctx.shadowBlur = 24; + + if (curr._on) + ctx.fillStyle = '#fff'; + else + ctx.fillStyle = '#686868'; + + ctx.stroke (); + ctx.fill (); + + ctx.shadowBlur = 0; + ctx.fillStyle = _fillstyle; + } + else if (curr._hov) { + + if (curr._on) + ctx.fillStyle = 'blue'; + else + ctx.fillStyle = 'darkblue'; + + ctx.stroke (); + ctx.fill (); + + ctx.fillStyle = _fillstyle; + } + else if (curr._on) { + ctx.fill (); + } + else { + ctx.fillStyle = '#555'; + ctx.fill (); + ctx.fillStyle = _fillstyle; + } + } + }; + + + _make_controls ( q ); + + // ------- + function _make_controls ( q ) { + var click_time = 0; + q.canvas.addEventListener ('click', function ( e ) { + if (!q.act) return; + if (e.timeStamp - click_time < 260) + { + var bounds = q.canvas.getBoundingClientRect (); + var cw = q.cw; + var ch = q.ch; + var posx = e.clientX - bounds.left; + var posy = e.clientY - bounds.top; + + var rel_x = posx / cw; + var rel_y = posy / ch; + + if (!q.points[q.act.id]) q.points[q.act.id] = []; + + var duration; + var region = q.wv.regions.list[0]; + if (region) { + duration = region.end - region.start; + } else { + duration = q.wv.getDuration(); + } + + q.points[q.act.id].push ({ + // el:q.act.el, + id: ++_pid, + x: rel_x, + y: rel_y, + ax: rel_x * cw, + ay: rel_y * ch, + time: duration * rel_x, + val : ((1 - rel_y) * (q.act.max - q.act.min)) + q.act.min, + _on: true, + _hov: false, + }); + + q.points[q.act.id].sort( _compare ); + q.act_point = q.points[q.act.id][q.points[q.act.id].length - 1]; + + //_process ( q, q.wv.backend.buffer ); + + q.Render (); + // ---- + } + + click_time = e.timeStamp; + }, false); + + var is_dragging = false; + var skip = 3; + q.canvas.addEventListener ('mousemove', function ( e ) { + if (!is_dragging || !q.act_point) return ; + + var ex = 0; + var ey = 0; + + if (e.touches) { + if (e.touches.length > 1) { return ; } + + ex = e.touches[0].clientX; + ey = e.touches[0].clientY; + } else { + ex = e.clientX; + ey = e.clientY; + } + + var bounds = q.canvas.getBoundingClientRect (); + var cw = q.cw; + var ch = q.ch; + + var posx = ex - bounds.left; + var posy = ey - bounds.top; + + var rel_x = posx / cw; + var rel_y = posy / ch; + + q.act_point.ax = posx; + q.act_point.ay = posy; + + q.act_point.x = rel_x; + q.act_point.y = rel_y; + + var duration; + var region = q.wv.regions.list[0]; + if (region) { + duration = region.end - region.start; + } else { + duration = q.wv.getDuration(); + } + + q.act_point.time = duration * rel_x; + q.act_point.val = ((1 - rel_y) * q.act.max - q.act.min) + q.act.min; + + q.Render (); + + if (--skip === 0) { + skip = 4; + _process ( q, q.wv.backend.buffer ); + } + }); + + q.canvas.addEventListener ('mousedown', function ( e ) { + is_dragging = false; + if (!q.act) return ; + + var bounds = q.canvas.getBoundingClientRect (); + var cw = q.cw; + var ch = q.ch; + + var posx = e.clientX - bounds.left; + var posy = e.clientY - bounds.top; + + var dist_x = e.is_touch ? 20 : 10; + var dist_y = e.is_touch ? 20 : 9; + + if (!q.points[q.act.id]) q.points[q.act.id] = []; + + for (var o = 0; o < q.points[q.act.id].length; ++o) + { + var curr = q.points[q.act.id][ o ]; + if ( Math.abs (curr.ax - posx) < dist_x && Math.abs (curr.ay - posy) < dist_y) + { + is_dragging = true; + q.act_point = curr; + q.Render (); + + break; + } + } + + if (!is_dragging) + { + q.act_point = null; + q.Render (); + } + }); + + q.canvas.addEventListener ('mouseup', function ( e ) { + is_dragging = false; + }); + + + var act_el = null; + q.modal.el_body.addEventListener ('mouseover', function(e) { + if (!q.in_auto) return ; + if (e.target.tagName === 'INPUT') { + e.target.classList.add ('pk_aut'); + } + }); + q.modal.el_body.addEventListener ('mouseout', function(e) { + if (!q.in_auto) return ; + if (e.target.tagName === 'INPUT') { + e.target.classList.remove ('pk_aut'); + } + }); + q.modal.el_body.addEventListener ('click', function(e) { + if (!q.in_auto) return ; + if (e.target.classList.contains ('pk_aut')) + { + if (act_el) { + act_el.classList.remove ('pk_aut_act'); + act_el = null; + } + + e.target.classList.add ('pk_aut_act'); + act_el = e.target; + + if (!e.target.id) e.target.id = 'pk' + (++_aid); + + q.act = { + id: e.target.id, + el: e.target, + type:e.target.range, + min:e.target.min/1, + max:e.target.max/1, + step:e.target.step/1 + }; + + if (!q.points[q.act.id]) q.points[q.act.id] = []; + + q.Render (); + } + + // console.log( 'click ', e.target ); + }); + }; + + + function _make_btn_auto ( q ) { + var btn_automate = d.createElement ('a'); + btn_automate.className = 'pk_modal_a_bottom'; + btn_automate.innerHTML = 'AUTOMATE'; + + var in_auto = false; + btn_automate.onclick = function () { + q.in_auto = !q.in_auto; + + if (q.in_auto) { + btn_automate.classList.add ('pk_act'); + } else { + btn_automate.classList.remove ('pk_act'); + } + }; + + q.modal.el_body.appendChild( btn_automate ); + + return (btn_automate); + }; + + function _make_canvas ( q ) { + var cc = document.createElement ('canvas'); + cc.width = 500; cc.height = 200; + cc.style.background = '#000'; + var ctx = cc.getContext('2d'); + + q.modal.el_body.appendChild( cc ); + + var buff = q.wv.backend.buffer; + + var img = new Image(); + img.onload = function () { + ctx.drawImage (img, 0, 0); + }; + + var offset; var length; + var region = q.wv.regions.list[0]; + if (region) { + offset = (region.start * buff.sampleRate) >> 0; + length = (region.end * buff.sampleRate) >> 0; + } + + _process ( q, buff ); + + img.src = q.app.engine.GetWave (buff, 500, 200, offset, length); + + return ([cc, ctx]); + }; + + function _compare ( a, b ) { + if (a.x > b.x) return 1; + return -1; + }; + + function _process ( q, buffer ) { + var getOfflineAudioContext = function (channels, sampleRate, duration) { + return new (window.OfflineAudioContext || + window.webkitOfflineAudioContext)(channels, duration, sampleRate); + }; + + var region = q.wv.regions.list[0]; + var offs = 0; + var durr = buffer.duration; + if (region) { + offs = region.start; + durr = region.end - region.start; + } + + var audio_ctx = getOfflineAudioContext ( + 1, // orig_buffer.numberOfChannels, + 8000, + (durr * 8000) >> 0 + ); + + var newbuffer = audio_ctx.createBuffer (1, durr * buffer.sampleRate, buffer.sampleRate); + newbuffer.getChannelData ( 0 ).set ( + buffer.getChannelData ( 0 ).slice ( (offs * buffer.sampleRate) / 4, ((offs + durr) * buffer.sampleRate)/4 ) + ); + + var source = audio_ctx.createBufferSource (); + source.buffer = newbuffer; + + //var fx = q.app.engine.GetFX ('Gain', q.GetValue ()); + //console.log ( fx.filter ( audio_ctx, audio_ctx.destination, source ) ); + + source.connect (audio_ctx.destination); + source.start (0); //, offs, durr); + + var offline_callback = function( rendered_buffer ) { + q.rbuff = rendered_buffer; + + debugger; + + // var img = new Image(); + // img.src = q.app.engine.GetWave (rendered_buffer, 500, 200); + + q.Render (); + + }; + var offline_renderer = audio_ctx.startRendering(); + if (offline_renderer) + offline_renderer.then( offline_callback ).catch(function(err) { + console.log('Rendering failed: ' + err); + }); + else + audio_ctx.oncomplete = function ( e ) { + offline_callback ( e.renderedBuffer ); + }; + + // --------- + }; + }; + + PKAudioEditor._deps.FxAUT = FXAutomation; + +})( window, document, PKAudioEditor ); \ No newline at end of file diff --git a/audiomass-editor/src/fx-pg-eq.js b/audiomass-editor/src/fx-pg-eq.js new file mode 100755 index 0000000..69f7af9 --- /dev/null +++ b/audiomass-editor/src/fx-pg-eq.js @@ -0,0 +1,3067 @@ +(function ( w, d, PKAE ) { + 'use strict'; + + var modal_name = 'modalfx'; + var modal_esc_key = modal_name + 'esc'; + var max_db_val = 35; + + function PK_FX_PGEQ () { + var q = this; + var _id = 0; + + var _is_render_scheduled = false; + var _is_render_scheduled2 = false; + + q.act = null; + q.ranges = []; + q.ui = {}; + + this.Callback = function(){}; + + this.Init = function ( container ) { + var q = this; + + q.el = container; + _make_ui ( q ); + _make_evs ( q ); + + q.Render (); + }; + + this.Add = function (type, is_on, freq, gain, qval, coords_x, coords_y) { + var q = this; + + var new_range = { + id: (++_id), + type: type ? type : 'peaking', + freq: freq || 0, + gain: gain || 0, + q: qval || 5, + + // interface + _on: is_on, + _hov: false, + _el: null, + _coords: { + x: coords_x || 0, + y: coords_y || 0 + }, + _arr:[] + }; + + q.ranges.push (new_range); + q.ranges.sort (_compare); + + if (q.act) { + q.act.el.classList.remove ('pk_act'); + } + + q.act = new_range; + + _range_compute_arr (new_range); + new_range.el = _range_render_el (q, new_range, ' pk_act'); + + q.Callback && q.Callback (); + + q.Render (); + }; + + this.Remove = function (range) { + var q = this; + + var l = q.ranges.length; + + while (l-- > 0) { + if (q.ranges[l] === range) { + q.ranges.splice (l, 1); + break; + } + } + + if (range.el) { + range.el.parentNode.removeChild (range.el); + range.el = null; + } + + if (q.act && q.act === range) { + q.act = null; + } + + q.Render (); + }; + + var _fillstyle = '#d9d955'; + + var _anim_render = function () { + _render ( q ); + }; + + this.Render = function () { + var q = this; + + if (_is_render_scheduled) return ; + _is_render_scheduled = true; + + requestAnimationFrame (_anim_render); + }; + + this.RenderBars = function (_, freq) { + var q = this; + + if (_is_render_scheduled2) return ; + _is_render_scheduled2 = true; + + requestAnimationFrame (function () { + _render_bars ( q, freq ); + }); + }; + + var _render_bars = function( q, freq ) { + _is_render_scheduled2 = false; + + if (!freq) return ; + + var ctx = q.ui.ctx_bars; + var canvas = q.ui.canvas_bars; + + var cw = canvas.width; + var ch = canvas.height; + + // ctx.fillStyle = '#000'; + // ctx.fillRect (0, 0, cw, ch); + ctx.clearRect (0, 0, cw, ch); + + var bufferLength = 512; // 256 + var max_bars = 117 * 2; + var barWidth = (cw / max_bars).toFixed(1)/1; + var barHeight = 0; + var x = 0; + + // + for (var i = 0; i < 117; ++i) + { + barHeight = freq[i]; + + // map.push ( i * 43 ); + + var newheight = ((barHeight / 256) * ch) >> 0; + + ctx.fillRect (x, ch - newheight, barWidth, newheight); + x += barWidth;// + 1; + } + + for (var i = 0; i < 117; ++i) + { + // (116*3.4) + barHeight = freq[117 + ((i * 3.34) >> 0)]; + + // map.push ( (120 + (i * 3)) * 43 ); + var newheight = ((barHeight / 256) * ch) >> 0; + + ctx.fillRect (x, ch - newheight, barWidth, newheight); + x += barWidth;// + 1; + } + +// console.log( map ); + + // what if we care for the small bars first +/* + var steps = (total_freq/bufferLength) >> 0; + + // we care for + + // 256 bars + + // 32 + // 64 + // 125 + // 250 + // 500 + // 1000 + // 2000 + // 4000 + // 8000 + // 16000 + // 20000 + var arr = [32, 64, 125, 250, 500, 1000, 2000, 4000, 8000, 16000, 20000]; + var curr = 0; + var curr_bars = 0; + var bars_per_entry = (bufferLength / 10) >> 0; + + for (var i = 0; i < bufferLength; ++i) { + + if (++curr_bars < bars_per_entry) + { + + var ff = arr[ curr ]; + var ff_next = arr[ curr + 1]; + + var m = 0; + for (; m < bufferLength; ++m) + { + if (m * steps > ff) { + --m; + break; + } + } + + barHeight = freq[ m ]; + + var newheight = ((barHeight / 256) * ch) >> 0; + ctx.fillRect (x, ch - newheight, barWidth, newheight); + x += barWidth;// + 1; + } + else + { + ++curr; + curr_bars = 0; + } + } +*/ + +// for (var i = 0; i < bufferLength; ++i) { +// barHeight = freq[i]; +// var newheight = ((barHeight / 256) * ch) >> 0; + +// ctx.fillRect (x, ch - newheight, barWidth, newheight); +// x += barWidth;// + 1; +// } + }; + + + + var line_arr = new Array (1000); + var _render = function ( q ) { + _is_render_scheduled = false; + + var ctx = q.ui.ctx_eq; + var canvas = q.ui.canvas_eq; + + var cw = canvas.width; + var ch = canvas.height; + + var ch_half = ch / 2; + + // -------------------- + ctx.clearRect (0, 0, cw, ch); + + ctx.fillStyle = _fillstyle; + + if (q.ranges.length === 0) + { + ctx.beginPath (); + ctx.moveTo (0, ch_half); + ctx.lineTo (cw, ch_half); + ctx.stroke (); + + return ; + } + + // render the line based on the elements + var first = true; + var arr = []; + for (var i = 0; i < total; ++i) { + arr[i] = 0; + } + + for (var o = 0; o < q.ranges.length; ++o) + { + var curr = q.ranges[ o ]; + + if (!curr._on) continue; + + if (first) + { + first = false; + for (var i = 0; i < total; ++i) + { + line_arr[i] = curr._arr[i]; + } + } + else + { + for (var i = 0; i < total; ++i) + { + line_arr[i] += curr._arr[i]; + } + } + // --- + } + + + if (first) + { + ctx.beginPath (); + ctx.moveTo (0, ch_half); + ctx.lineTo (cw, ch_half); + ctx.stroke (); + } + else + { + // -- + ctx.beginPath (); + ctx.moveTo ( 0, ch_half - (line_arr[ 0 ] * (ch_half / max_db_val)) ); + + for (var i = 0; i < (total / 4); i += 1) { + var el = line_arr[ i ]; + + var x = (i * 2) * (cw / total); + var y = ch_half - (el * (ch_half / max_db_val)); + + ctx.lineTo ( x, y ); + } + + var hh = 0; + for (var i = (total / 4); i < total; i += 3) { + var el = line_arr[ i ]; + + hh += 2; + + var x = ((total / 2) + hh) * (cw / total); + var y = ch_half - (el * (ch_half / max_db_val)); + + ctx.lineTo ( x, y ); + } + + ctx.stroke (); + } + // --- + + + // draw the dots + var radius = 6; + for (var o = 0; o < q.ranges.length; ++o) + { + var curr = q.ranges[ o ]; + + var center_x = curr._coords.x; + var center_y = curr._coords.y; + + ctx.beginPath (); + ctx.arc (center_x, center_y, radius, 0, 2 * Math.PI, false); + + if (curr === q.act) { + ctx.shadowBlur = 24; + + if (curr._on) + ctx.fillStyle = '#fff'; + else + ctx.fillStyle = '#686868'; + + ctx.stroke (); + ctx.fill (); + + ctx.shadowBlur = 0; + ctx.fillStyle = _fillstyle; + } + else if (curr._hov) { + + if (curr._on) + ctx.fillStyle = 'blue'; + else + ctx.fillStyle = 'darkblue'; + + ctx.stroke (); + ctx.fill (); + + ctx.fillStyle = _fillstyle; + } + else if (curr._on) { + ctx.fill (); + } + else { + ctx.fillStyle = '#555'; + ctx.fill (); + ctx.fillStyle = _fillstyle; + } + } + + // --- + }; + + + + //////////////////////////////////////////// + // helpers + var _dbncr = null; + var total_freq = 20000; // 22000 + var total = 1000; + var jump = (total_freq / total) >> 0; + + function _range_update ( q, range, new_range, compute_coords ) { + var modified = false; + var old_val = null; + + for (var key in new_range) + { + if (range[key] !== new_range[key]) + { + modified = true; + old_val = range[key]; + range[key] = new_range[key]; + + if (key === '_on') + { + var el = document.getElementById ('pgon' + range.id); + el.checked = range[key]; + } + else if (key === 'freq') + { + var el = range.el.getElementsByClassName('pk_freq')[0]; + //requestAnimationFrame (function () { + el.value = range[key]; + //}); + } + else if (key === 'gain') + { + var el = range.el.getElementsByClassName('pk_gain')[0]; + //requestAnimationFrame (function () { + el.value = range[key]; + //}); + } + else if (key === 'q') + { + var el = range.el.getElementsByClassName('pk_q')[0]; + //requestAnimationFrame (function () { + el.value = range[key]; + //}); + } + else if (key === 'type') + { + // ----- + var el = range.el.getElementsByTagName('select')[0]; + if (range[key] === 'peaking') el.options[0].selected = true; + else if (range[key] === 'lowpass') el.options[1].selected = true; + else if (range[key] === 'highpass') el.options[2].selected = true; + + _range_compute_arr (range); + q.ranges.sort (_compare); + } + // --- + } + } + + if (modified) + { + if (compute_coords) + { + // compute coords of the canvas + var canvas = q.ui.canvas_eq; + var cw = canvas.width; + var ch = canvas.height; + + var tmp_x = 0; + if (range.freq <= 5000) { + range._coords.x = ((range.freq / 5000) * (cw / 2) ).toFixed(1)/1; + } else { + range._coords.x = ((cw / 2) + (((range.freq - 5000) / 15000) * (cw / 2))).toFixed(1)/1; + } + + // range._coords.x = ((range.freq / total_freq) * cw).toFixed(1)/1; + + if (range.type === 'peaking') + range._coords.y = ((1.0 - ((range.gain + max_db_val) / (max_db_val * 2))) * ch).toFixed(1)/1; + else + range._coords.y = (ch / 2).toFixed(1)/1; + } + + if (_dbncr) { + clearTimeout (_dbncr); + } + + _dbncr = setTimeout (function () { + q.Callback (); + _dbncr = null; + }, 38); + + q.Render (); + } + // --- + }; + + function _ease (t) { return t*t*t*t*t }; + function _ease_out (t) { return t*t*t*t }; + + function _range_compute_arr ( range ) { + var arr = []; + + for (var i = 0; i < total; ++i) { + arr[i] = 0; + } + + range._arr = arr; + + // ------------- + var rounding = total_freq * (2 / range.q); + var half_rounding = (rounding / jump) >> 0; + + if (range.type === 'peaking') + { + var edge_left = range.freq - (rounding / 2); + var edge_right = range.freq + (rounding / 2); + + var start = (edge_left / jump) >> 0; + var end = (edge_right / jump) >> 0; + + var j = 0; + for (var i = start; i < end; ++i) + { + var ii = (i * jump); + if (ii < range.freq) + { + ++j; + arr[i] += _ease (j / (half_rounding / 2)) * range.gain; + } + else + { + --j; + arr[i] += _ease (j / (half_rounding / 2)) * range.gain; + } + } + + return ; + } + + if (range.type === 'highpass') + { + var edge_left = range.freq - rounding; + var start = (edge_left / jump) >> 0; + var end = (range.freq / jump) >> 0; + + for (var i = 0; i < start; ++i) + { + arr[i] = -max_db_val; + } + + // todo improve this!!! + var j = half_rounding; + for (var i = start; i < end; ++i) + { + --j; + arr[i] -= _ease_out (j / half_rounding) * max_db_val; + } + + return ; + } + + if (range.type === 'lowpass') + { + var edge_right = range.freq + rounding; + var start = (range.freq / jump) >> 0; + var end = (edge_right / jump) >> 0; + + for (var i = end; i < total; ++i) + { + arr[i] = -max_db_val; + } + + // todo improve this!!! + var j = 0; + for (var i = start; i < end; ++i) + { + ++j; + arr[i] -= _ease_out (j / half_rounding) * max_db_val; + } + + return ; + } + + // ------------- + } + + function _make_ui ( q ) { + var el_drawer = d.createElement ('div'); + el_drawer.className = 'pk_row'; + + var canvas_bars = d.createElement ('canvas'); + var canvas_eq = d.createElement ('canvas'); + + canvas_bars.className = 'pk_peq2'; + canvas_eq.className = 'pk_peq'; + + canvas_bars.width = 450 / 2; + canvas_bars.height = 224 / 2; + + canvas_eq.width = 450; + canvas_eq.height = 225; + + var ctx_bars = canvas_bars.getContext ('2d', {alpha:true, antialias:false}); + var ctx_eq = canvas_eq.getContext ('2d', {alpha:true, antialias:false}); + + ctx_bars.fillStyle = '#365457'; // '#486a6e'; + + // ctx_eq.lineWidth = 2; + ctx_eq.strokeStyle = '#FF0000'; + ctx_eq.shadowColor = '#FF2222'; + ctx_eq.shadowBlur = 0; + + + // render the decibel and the frequencies + var marker_freqs = d.createElement ('div'); + marker_freqs.className = 'pk_peq3 pk_noselect'; + marker_freqs.innerHTML = '32' + +// '32' + +// '64' + +// '128' + +// '250' + +// '500' + + '500' + + '1k' + + '2k' + + '4k' + + '5k' + + '8k' + + '12k' + + '16k' + + '20k'; + + + var marker_dbs = d.createElement ('div'); + marker_dbs.className = 'pk_peq4 pk_noselect'; + marker_dbs.innerHTML = '35' + + '28' + + '21' + + '14' + + '7' + + '0' + + '-7' + + '-14' + + '-21' + + '-28' + + '35'; + + el_drawer.appendChild ( canvas_bars ); + el_drawer.appendChild ( canvas_eq ); + el_drawer.appendChild ( marker_freqs ); + el_drawer.appendChild ( marker_dbs ); + + q.el.appendChild ( el_drawer ); + + // element's area + var el_list = document.createElement ('div'); + el_list.className = 'pk_row pk_noselect pk_pglst'; + + el_list.innerHTML = '
' + + ' #typegainfreqQ' + + '
'; + + q.el.appendChild ( el_list ); + + q.ui.ctx_bars = ctx_bars; + q.ui.ctx_eq = ctx_eq; + + q.ui.canvas_bars = canvas_bars; + q.ui.canvas_eq = canvas_eq; + q.ui.el_list = el_list; + } + + function _make_evs ( q ) { + var ctx = q.ui.ctx_eq; + var canvas = q.ui.canvas_eq; + + var click_time = 0; + var is_dragging = false; + + + var _move = function ( e ) { + if (!is_dragging || !q.act) return ; + + var ex = 0; + var ey = 0; + + if (e.touches) { + if (e.touches.length > 1) { return ; } + + ex = e.touches[0].clientX; + ey = e.touches[0].clientY; + } else { + ex = e.clientX; + ey = e.clientY; + } + + var bounds = canvas.getBoundingClientRect (); + var cw = canvas.width; + var ch = canvas.height; + + var posx = ex - bounds.left; + var posy = ey - bounds.top; + + var rel_x = posx / cw; + var rel_y = posy / ch; + + q.act._coords.x = posx; + q.act._coords.y = posy; + + // up until half it's 0 - 5000, second half 5000 -> 2200 + var freq = 0; + + if (rel_x <= 0.5) { + freq = (5000 * (rel_x * 2)) >> 0 + } else { + freq = 5000 + ((((rel_x - 0.5) * 2) * 15000) >> 0); + } + +// var freq = (rel_x * (total_freq) + 0) >> 0; // + 16 (min freq) + var gain = (((rel_y - 0.5) * -2) * max_db_val).toFixed (2) / 1; + + _range_update (q, q.act, { + 'freq': freq, + 'gain': gain + }); + _range_compute_arr (q.act); + }; + + var _end = function ( e ) { + is_dragging = false; + + canvas.removeEventListener ('mousemove', _move); + canvas.removeEventListener ('mouseup', _end); + + canvas.removeEventListener ('touchmove', _move); + canvas.removeEventListener ('touchup', _end); + }; + + var mdown = function ( e ) { + var unchecked = !!q.act; + + if (q.ranges.length === 0) + { + if (unchecked) q.Render (); + return ; + } + + var bounds = canvas.getBoundingClientRect (); + var cw = canvas.width; + var ch = canvas.height; + + var posx = e.clientX - bounds.left; + var posy = e.clientY - bounds.top; + + var dist_x = e.is_touch ? 20 : 10; + var dist_y = e.is_touch ? 20 : 9; + + for (var o = 0; o < q.ranges.length; ++o) + { + var curr = q.ranges[ o ]; + + if ( Math.abs (curr._coords.x - posx) < dist_x && Math.abs (curr._coords.y - posy) < dist_y) + { + if (unchecked) { + q.act.el.classList.remove ('pk_act'); + } + + q.act = curr; + q.act.el.classList.add ('pk_act'); + + is_dragging = true; + + q.Render (); + + // check if we are targetting a circle + + if (!e.is_touch) + { + canvas.addEventListener ('mousemove', _move, false); + canvas.addEventListener ('mouseup', _end, false); + } + else + { + e.ev.preventDefault (); + e.ev.stopPropagation (); + + canvas.addEventListener ('touchmove', _move, false); + canvas.addEventListener ('touchup', _end, false); + } + + return ; + } + // --- + } + + if (unchecked) { + q.act.el.classList.remove ('pk_act'); + // un-highlight + q.act = null; + + q.Render (); + } + + // ---- + }; + + canvas.addEventListener ('mousedown', mdown, false); + + + canvas.addEventListener ('touchstart', function ( e ) { + if (e.touches.length > 1) { + e.preventDefault (); + e.stopPropagation (); + + return ; + } + + var ev = { + clientX : e.touches[0].clientX, + clientY : e.touches[0].clientY, + is_touch : true, + ev : e + }; + + mdown ( ev ); + }); + + + canvas.addEventListener ('click', function ( e ) { + if (e.timeStamp - click_time < 260) + { + var bounds = canvas.getBoundingClientRect (); + var cw = canvas.width; + var ch = canvas.height; + var posx = e.clientX - bounds.left; + var posy = e.clientY - bounds.top; + + var rel_x = posx / cw; + var rel_y = posy / ch; + + var freq = 0; + if (rel_x <= 0.5) { + freq = (5000 * (rel_x * 2)) >> 0 + } else { + freq = 5000 + ((((rel_x - 0.5) * 2) * 15000) >> 0); + } + + // var freq = (rel_x * (total_freq) + 0) >> 0; // + 16 (min freq) + var gain = (((rel_y - 0.5) * -2) * max_db_val).toFixed(2)/1; + var qval = 5; + var type = 'peaking'; + + q.Add (type, true, freq, gain, qval, posx, posy); + } + + click_time = e.timeStamp; + }, false); + + // --- + + } + + function _range_render_el ( q, range, clss ) { + var el_list = q.ui.el_list; + + var el = d.createElement ('div'); + el.className = 'pk_pgeq_els' + (clss ? clss : ''); + el.setAttribute ('data-id', range.id); + + el.addEventListener ('click', function ( e ) { + if (!range.el) return ; + + if (range !== q.act) + { + if (q.act) + { + q.act.el.classList.remove ('pk_act'); + } + + q.act = range; + q.act.el.classList.add ('pk_act'); + + q.Render (); + } + }, false); + + el.addEventListener ('mouseover', function ( e ) { + if (!range.el) return ; + + if (!range._hov) + { + range._hov = true; + q.Render (); + } + }, false); + + el.addEventListener ('mouseleave', function ( e ) { + if (!range.el) return ; + + if (range._hov) + { + range._hov = false; + q.Render (); + } + }, false); + + // # & on or off + var chckd = range._on ? 'checked' : ''; + var num = '' + range.id + ''; + var el_num = d.createElement ('div'); + el_num.className = 'pk_txlft'; + el_num.innerHTML = num + + '' + + ''; + + el_num.getElementsByTagName('input')[0].onchange = function ( e ) { + _range_update (q, range, {'_on': !!this.checked}); + + var lbl = this.parentNode.getElementsByTagName('label')[0]; + lbl.innerHTML = this.checked ? 'ON' : 'OFF'; + }; + el.appendChild (el_num); + + // type + var sel1 = range.type === 'lowpass' ? 'selected' : ''; + var sel2 = range.type === 'highpass' ? 'selected' : ''; + var el_type = d.createElement ('div'); + el_type.innerHTML = ''; + + el_type.getElementsByTagName('select')[0].onchange = function ( e ) { + var val = this.options[this.selectedIndex].value; + + if (val === 'peaking') { + el.classList.remove ('pk_dis'); + } else { + el.classList.add ('pk_dis'); + } + + _range_update (q, range, {'type': val}, 1); + }; + + el.appendChild (el_type); + + // gain + var el_gain = d.createElement ('div'); + el_gain.innerHTML = ''; + + el_gain.getElementsByClassName('pk_gain')[0].onchange = function ( e ) { + if (!this.value) { + this.value = 0; + } + + if (this.hasAttribute ('data-open')) { + this.parentNode.getElementsByClassName('pk_horiz')[0].value = this.value; + } + + _range_update (q, range, {'gain': this.value / 1}, 1); + _range_compute_arr (range); + }; + el_gain.getElementsByClassName('pk_gain')[0].onfocus = function ( e ) { + if (this.hasAttribute ('data-open')) return ; + + var self = this; + var parent = this.parentNode; + var bar = document.createElement ('div'); + bar.className = 'pk_pgeq_freq pk_gain'; + bar.innerHTML = '
'; + + bar.getElementsByClassName('pk_horiz')[0].oninput = function ( e ) { + if (self.value != this.value) { + self.value = this.value; + self.onchange (); + } + }; + + parent.appendChild (bar); + this.setAttribute('data-open', '1'); + + var down = function ( e ) { + if ( !e.target.classList.contains ('pk_gain') || (e.target.type === self.type && e.target !== self) ) + { + self.removeAttribute ('data-open'); + parent.removeChild (bar); + q.el.removeEventListener ('mousedown', down); + return ; + } + }; + q.el.addEventListener ('mousedown', down, false); + }; + el.appendChild (el_gain); + + // freq + var el_freq = d.createElement ('div'); + el_freq.innerHTML = ''; + el_freq.getElementsByClassName('pk_freq')[0].onchange = function ( e ) { + if (!this.value) { + this.value = 500; + } + + if (this.hasAttribute ('data-open')) { + this.parentNode.getElementsByClassName('pk_horiz')[0].value = this.value; + } + + _range_update (q, range, {'freq': this.value / 1}, 1); + _range_compute_arr (range); + }; + + el_freq.getElementsByClassName('pk_freq')[0].onfocus = function ( e ) { + if (this.hasAttribute ('data-open')) return ; + + var self = this; + var parent = this.parentNode; + var bar = document.createElement ('div'); + bar.className = 'pk_pgeq_freq pk_freq'; + bar.innerHTML = '
'; + + bar.getElementsByClassName('pk_horiz')[0].oninput = function ( e ) { + if (self.value != this.value) { + self.value = this.value; + self.onchange (); + } + }; + + parent.appendChild (bar); + this.setAttribute('data-open', '1'); + + var down = function ( e ) { + if ( !e.target.classList.contains ('pk_freq') || (e.target.type === self.type && e.target !== self) ) + { + self.removeAttribute ('data-open'); + parent.removeChild (bar); + q.el.removeEventListener ('mousedown', down); + } + }; + q.el.addEventListener ('mousedown', down, false); + }; + + el.appendChild (el_freq); + + // q + var el_q = d.createElement ('div'); + el_q.innerHTML = ''; + el_q.getElementsByClassName('pk_q')[0].onchange = function ( e ) { + + if (!this.value) { + this.value = 1; + } + + if (this.hasAttribute ('data-open')) { + this.parentNode.getElementsByClassName('pk_horiz')[0].value = this.value; + } + + _range_update (q, range, {'q': this.value / 1}, 1); + _range_compute_arr (range); + }; + + el_q.getElementsByClassName('pk_q')[0].onfocus = function ( e ) { + if (this.hasAttribute ('data-open')) return ; + + var self = this; + var parent = this.parentNode; + var bar = document.createElement ('div'); + bar.className = 'pk_pgeq_freq pk_q'; + bar.innerHTML = '
'; + + bar.getElementsByClassName('pk_horiz')[0].oninput = function ( e ) { + if (self.value != this.value) { + self.value = this.value; + self.onchange (); + } + }; + + parent.appendChild (bar); + this.setAttribute('data-open', '1'); + + var down = function ( e ) { + if ( !e.target.classList.contains ('pk_q') || (e.target.type === self.type && e.target !== self) ) + { + self.removeAttribute ('data-open'); + parent.removeChild (bar); + q.el.removeEventListener ('mousedown', down); + } + }; + q.el.addEventListener ('mousedown', down, false); + }; + el.appendChild (el_q); + + // delete + var el_del = d.createElement ('div'); + el_del.className = 'pk_del'; + el_del.innerHTML = 'DELETE'; + el_del.getElementsByTagName('a')[0].onclick = function ( e ) { + q.Remove (range); + }; + + el.appendChild (el_del); + + // ---------------------- + el_list.appendChild (el); + + return (el); + } + + function _compare ( a, b ) { + if (a.type === 'peaking' && b.type !== 'peaking') return -1; + if (b.type === 'peaking' && a.type !== 'peaking') return 1; + + return 0; + } + // --- + }; + + + var ParagraphicModal = function ( app, custom_presets ) { + + app.fireEvent ('RequestSelect', 1); + + var filter_id = 'paragraphic_eq'; + + // ------- + var PGEQ = new PK_FX_PGEQ (); + var DrawBars = function (_, freq) { + PGEQ.RenderBars (_, freq); + }; + var updateFilter = function () { + if (!PGEQ) return ; + + var val = []; + var ranges = PGEQ.ranges; + + for (var i = 0; i < ranges.length; ++i) + { + var range = ranges [ i ]; + if (range._on) + { + val.push ({ + 'type' : range.type, + 'freq' : range.freq, + 'val' : range.gain, + 'q' : range.q + }); + } + } + return (val); + }; + + var x = new PKAudioFXModal ({ + id: filter_id, + title: 'Paragraphic EQ', + + ondestroy: function ( q ) { + app.stopListeningFor ('DidAudioProcess', DrawBars); + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback (modal_esc_key); + + PGEQ = null; + }, + + preview: function ( q ) { + app.fireEvent ('RequestActionFX_PREVIEW_PARAMEQ', updateFilter ()); + }, + + body: '', + + presets:[ + {name:'Old Telephone',val:'1,highpass,0,5800,5.8,1,lowpass,0,7060,5'} + ], + + custom_pres:custom_presets.Get (filter_id), + + onpreset: function ( val ) { + var l = PGEQ.ranges.length; + while (l-- > 0) { + PGEQ.Remove (PGEQ.ranges[l]); + } + + var canvas = PGEQ.ui.canvas_eq; + var cw = canvas.width; + var ch = canvas.height; + + var list = val.split(','); + var len = list.length; + var els = (len / 5) >> 0; + + for (var j = 0; j < els; ++j) + { + var curr = []; + var offset = j * 5; + + curr[0] = !!(list[ offset + 0 ] / 1); + curr[1] = list[ offset + 1 ]; + curr[2] = list[ offset + 2 ] / 1; + curr[3] = list[ offset + 3 ] / 1; + curr[4] = list[ offset + 4 ] / 1; + + var x = 0; + var y = 0; + + if (curr[3] < 5000) { + x = (curr[3] / 5000) * (cw / 2); + } else { + x = ((cw / 2) + (((curr[3] - 5000) / 15000) * (cw / 2))).toFixed(1)/1; + } + + if (curr[1] === 'peaking') + y = ((1.0 - (((curr[2]/1) + max_db_val) / (max_db_val * 2))) * ch).toFixed(1)/1; + else + y = (ch / 2).toFixed(1)/1; + + // (type, is_on, freq, gain, qval, coords_x, coords_y) + PGEQ.Add (curr[1], !!curr[0], curr[3]/1, curr[2]/1, curr[4]/1, x, y); + } + }, + + buttons: [{ + title:'Apply EQ', + clss:'pk_modal_a_accpt', + callback: function( q ) { + + app.fireEvent ('RequestActionFX_PARAMEQ', updateFilter ()); + q.Destroy (); + } + }], + + setup:function( q ) { + PGEQ.Init ( q.el_body ); + + PGEQ.Callback = function () { + app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', updateFilter ()); + }; + + app.listenFor ('DidAudioProcess', DrawBars); + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet (modal_name); + app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + q.Destroy (); + }, [27]); + } + }, app); + + x.Show (); + }; + + PKAudioEditor._deps.FxEQ = ParagraphicModal; + + + + + + + + + /////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + function getOfflineAudioContext (channels, sampleRate, duration) { + return new (window.OfflineAudioContext || + window.webkitOfflineAudioContext)(channels, duration, sampleRate); + }; + function _normalize_array (data) { + var new_array = []; + for (var i = 0; i < data.length; ++i) { + new_array.push ( Math.abs (Math.round ((data[i + 1] - data[i]) * 1000)) ); + } + + return (new_array); + }; + + function _normalize_array2 (data) { + var new_array = []; + for (var i = 0; i < data.length; ++i) { + new_array.push ( Math.round (Math.abs (data[i] * 1000)) ); + } + + return (new_array); + }; + + function _group_rhythm ( data, diff_arr ) { + if (diff_arr.length <= 1) return ; + + var peak_median = 0; + for (var i = 0; i < data.length; ++i) { + peak_median += data[i]; + } + + peak_median /= diff_arr.length; + peak_median -= peak_median * 0.2; + + var diff_median = 0; + for (var i = 0; i < diff_arr.length; ++i) { + diff_median += diff_arr[i]; + } + + diff_median /= diff_arr.length; + if (diff_median > 1) diff_median -= (diff_median * 0.2); + + var existing = 0; + for (var i = 0; i < diff_arr.length; ++i) { + if (diff_arr[i] <= diff_median) continue; + ++existing; + } + + // console.log (" DIFF MEDIAN IS ", diff_median, " and total beats: ", existing, " out of: ", diff_arr.length); + // clean-up the drums array - based on the median. + // console.log ( JSON.stringify( data ) ); + // console.log ("----------"); + + for (var i = 0, j = 0; i < data.length; ++i) + { + if (data[i] !== 0) { + + if (diff_arr[j] && diff_arr[j] < diff_median) { + + if (data[i] > peak_median && diff_arr[j] > (diff_median * 0.6)){ + //console.log ( 'ZEROEDC NOOOOT ', i, ' ', data[i], ' with median ', peak_median , ' but diff was ', diff_arr[j], ' yet. ', diff_median ); + } + else { + //console.log ( 'ZEROEDC ', i, ' ', data[i], ' with median ', peak_median , ' but diff was ', diff_arr[j], ' yet. ', diff_median ); + data[i] = 0; + } + } + + ++j; + } + // ---- + } + + // console.log( data ); + window.final_arr = data; + + // console.log ( JSON.stringify( data ) ); + + // now count distance between peaks + var distances = {}; + var unique_distances = []; + var first_found = 0; + var is_first = true; + for (var i = 0; i < data.length - 1; ++i) // #### do not litter the last data + { + if (data[i] === 0) { + ++first_found; + continue; + } + + //if (first_found < 1 && !is_first) { + // continue; + //} + + if (is_first) { + is_first = false; + } + + first_found = 0; + + var own = []; + unique_distances.push (own); + + // console.log ('----------------------------------'); + // console.log ('COMPUTING DISTANCE OF ' + i + ' value ' + data[i] ); + + var interval = 0; + var total = 12; + var last_found = 0; + for (var j = i + 1; j < 1000; ++j) { + if (data[j] === 0) { ++interval; ++last_found; continue; } + else if (!data[j]) { break; } + + if (last_found < 0) { + continue; + } + last_found = 0; + + if (--total === 0) break; + + own.push (interval); + + // if it exists, immediately reach out for the next one. + if (!distances[interval]) distances[interval] = 0; + distances[interval] += 1; + + // console.log ('distance with index ' + j + ' value ' + data[j] + ' is ' + interval ); + } + // break; + } + + console.log(unique_distances); + + // grab only the big peaks. + + function getmax (a) { + var m = -Infinity, + i = 0, + n = a.length; + + for (; i != n; ++i) { + if (a[i] > m) { + m = a[i]; + } + } + return m; + } + + function getmin (a) { + var m = Infinity, + i = 0, + n = a.length; + + for (; i != n; ++i) { + if (a[i] !== 0 && a[i] < m) { + m = a[i]; + } + } + return m; + } + + var max = getmax (data); + var min = getmin (data); + var count = 0; + var threshold = Math.round ((max - min) * 0.3); + + var velocities = []; + for (var i = 0; i < data.length; ++i) { + if (data[i] === 0) continue; + + if (data[i] >= (max - threshold)) { + velocities.push (3); + } + else if (data[i] >= (max - (threshold * 2))) { + velocities.push (2); + } + else if (data[i] >= (max - (threshold * 3))) { + velocities.push (1); + } + else { + velocities.push (0); + } + } + + + return ([distances, velocities]); + }; + + var TempoToolsModal = function ( app ) { + app.fireEvent ('RequestSelect', 1); + var filter_id = 'tempo_tools'; + var act_index = 1; + var act_tool = null; + + // ------ + var TempoMetro = function ( app, modal ) { + var q = this; + q.app = app; + + var bpm = 120; + var tick = null; + var count = 0; + var time = ((60.0 / bpm) * 1000) >> 0; + var audioContext = null; // new AudioContext(); + var osc = null; + var amp = null; + var ready = false; + var volume = 0.5; + var accentuate = true; + + var DidStopPlay = null; + var DidPlay = null; + var MetronomeAct = null; + var MetronomeInAct = null; + + q.Init = function ( container ) { + var q = this; + + q.el = container; + + _make_ui ( q ); + _make_evs ( q ); + }; + + q.Destroy = function () { + q.app.stopListeningFor ('DidStopPlay', DidStopPlay); + q.app.stopListeningFor ('DidPlay', DidPlay); + q.app.stopListeningFor ('DidStartMetro', MetronomeAct); + q.app.stopListeningFor ('DidStopMetro', MetronomeInAct); + + DidStopPlay = null; + DidPlay = null; + MetronomeAct = null; + MetronomeInAct = null; + + if (ready) { + if (tick) { + clearTimeout (tick); + tick = null; + } + + if (audioContext) { + var now = audioContext.currentTime; + osc.stop (now); + + amp.disconnect (); + osc.disconnect (); + + audioContext = null; + + ready = false; + } + } + + if (q.body) { + q.body.parentNode.removeChild ( q.body ); + q.body = null; + } + + q.app = null; + }; + + function _make_ui ( q ) { + var el_drawer = d.createElement ('div'); + el_drawer.className = 'pk_row'; + + el_drawer.innerHTML = '
'+ + ''+ + ''+ + '120'+ + '
'+ + + '
'+ + ''+ + ''+ + '50%'+ + '
'+ + + '
'+ + ''+ + '
' + + + '
'+ + 'Metronome'+ + 'Play Track'+ + 'Play Both'+ + '
'; + + q.body = el_drawer; + q.el.appendChild ( el_drawer ); + }; + + function _make_evs ( q ) { + var range = q.body.getElementsByClassName('pk_horiz')[0]; + var span = q.body.getElementsByClassName('pk_val')[0]; + + var range2 = q.body.getElementsByClassName('pk_horiz')[1]; + var span2 = q.body.getElementsByClassName('pk_val')[1]; + + var checkbox = q.body.getElementsByClassName('pk_check')[0]; + + range.oninput = function() { + bpm = (range.value/1); + span.innerHTML = bpm; + + time = ((60.0 / bpm) * 1000) >> 0; + }; + + range2.oninput = function() { + var val = (range2.value/1); + volume = val; + + span2.innerHTML = ((val*100) >> 0) + '%'; + }; + + checkbox.oninput = function() { + accentuate = checkbox.checked; + }; + + var metronome_btn = q.body.getElementsByClassName ('pk_modal_a_bottom')[0]; + var play_btn = q.body.getElementsByClassName ('pk_modal_a_bottom')[1]; + var both_btn = q.body.getElementsByClassName ('pk_modal_a_bottom')[2]; + + metronome_btn.onclick = function () { + if (tick) { + clearTimeout (tick); + tick = null; + count = 0; + + q.app.fireEvent ('DidStopMetro'); + return ; + } + + var play = function () { + tick = setTimeout (function() { + if (!tick) return ; + + if (++count % 4 === 0) + _metronome (1); + else + _metronome (0); + + play (); + }, time); + }; + + count = 0; + if (!ready) _prepare (); + + q.app.fireEvent ('DidStartMetro'); + + _metronome (1); + play (); + }; + + MetronomeInAct = function() { + metronome_btn.classList.remove ('pk_act'); + }; + MetronomeAct = function() { + metronome_btn.classList.add ('pk_act'); + }; + q.app.listenFor ('DidStartMetro', MetronomeAct); + q.app.listenFor ('DidStopMetro', MetronomeInAct); + + play_btn.onclick = function () { + if (PKAudioEditor.engine.wavesurfer.isPlaying()) { + q.app.fireEvent ('RequestStop'); + } + else { + q.app.fireEvent ('RequestPlay'); + } + }; + if (!PKAudioEditor.engine.wavesurfer.isReady) + { + play_btn.className += ' pk_inact'; + both_btn.className += ' pk_inact'; + } + + if (PKAudioEditor.engine.wavesurfer.isPlaying()) { + play_btn.className += ' pk_act'; + } + + DidStopPlay = function() { + play_btn.classList.remove ('pk_act'); + play_btn.innerText = 'Play Track'; + }; + DidPlay = function() { + play_btn.classList.add ('pk_act'); + play_btn.innerText = 'Stop Track'; + }; + q.app.listenFor ('DidStopPlay', DidStopPlay); + q.app.listenFor ('DidPlay', DidPlay); + + both_btn.onclick = function () { + if (tick) metronome_btn.onclick (); + if (PKAudioEditor.engine.wavesurfer.isPlaying()) play_btn.onclick (); + + setTimeout(function() { + if (!tick && !PKAudioEditor.engine.wavesurfer.isPlaying()) + { + play_btn.onclick (); + setTimeout(function(){ + metronome_btn.onclick (); + },0); + } + },66); + }; + }; + + function _metronome ( type ) { + if (type === 1 && accentuate) { + osc.frequency.value = 880.0; + } else { + osc.frequency.value = 440.0; + } + + amp.gain.setValueAtTime (amp.gain.value, audioContext.currentTime); + amp.gain.linearRampToValueAtTime (volume, audioContext.currentTime + 0.01); + amp.gain.linearRampToValueAtTime (0.0, audioContext.currentTime + 0.12); + }; + + function _prepare () { + audioContext = new (window.AudioContext || window.webkitAudioContext)(); + + osc = audioContext.createOscillator (); + amp = audioContext.createGain(); + amp.gain.value = 0; + + osc.connect (amp); + amp.connect (audioContext.destination); + + osc.start (0); + + ready = true; + // osc.stop( time + 0.05 ); + }; + }; + + var TempoTap = function ( app, modal ) { + var q = this; + q.app = app; + + var DidStopPlay = null; + var DidPlay = null; + var DidSetLoop = null; + var DidAudioProcess = null; + + q.Init = function ( container ) { + var q = this; + + q.el = container; + + _make_ui ( q ); + _make_evs ( q ); + }; + + q.Destroy = function () { + q.app.stopListeningFor ('DidStopPlay', DidStopPlay); + q.app.stopListeningFor ('DidPlay', DidPlay); + q.app.stopListeningFor ('DidSetLoop', DidSetLoop); + q.app.stopListeningFor ('DidAudioProcess', DidAudioProcess); + + DidStopPlay = null; + DidPlay = null; + DidSetLoop = null; + DidAudioProcess = null; + + q.app.ui.KeyHandler.removeCallback ('tmpTap'); + + if (q.body) { + q.body.parentNode.removeChild ( q.body ); + q.body = null; + } + + q.app = null; + }; + + function _make_ui ( q ) { + var el_drawer = d.createElement ('div'); + el_drawer.className = 'pk_row'; + + // Estimate tempo for selected area button + el_drawer.innerHTML = '
' + + 'Average BPM'+ + ''+ + '
'+ + + '
'+ + 'Nearest BPM'+ + ''+ + '
'+ + + '
'+ + 'Timing Taps'+ + ''+ + 'Reset'+ + 'Play Track'+ + 'Loop'+ + '
'+ + + '
'+ + 'CLEARED...'+ + 'STAND BY...'+ + '
'+ + + '
'+ + ''+ + ''+ + '
'+ + + '
'+ + ''+ + 'Tap in this area, or hit [SPACE] rhythmically, to measure BPM.'+ + ''+ + '
'; + + q.body = el_drawer; + q.el.appendChild ( el_drawer ); + }; + + function _make_evs ( q ) { + var tap_graph = q.body.querySelectorAll('#pk_tmp_tap')[0]; + var tap_area = q.body.querySelectorAll('#pk_tmp_tap3')[0]; + var reset_btn = q.body.getElementsByClassName ('pk_modal_a_bottom')[0]; + var play_btn = q.body.getElementsByClassName ('pk_modal_a_bottom')[1]; + var loop_btn = q.body.getElementsByClassName ('pk_modal_a_bottom')[2]; + + var canvas = q.body.getElementsByTagName('canvas')[0]; + var ctx = canvas.getContext('2d', {alpha:false,antialias:false}); + + var tempCanvas = document.createElement('canvas'); + tempCanvas.width = 500 * 2; + tempCanvas.height = 100 * 2; + var tempCtx = tempCanvas.getContext ('2d', {alpha:false,antialias:false}); + + ctx.imageSmoothingEnabled = true; + tempCtx.imageSmoothingEnabled = true; + + var value_els = q.body.getElementsByClassName ('pk_val'); + var tap_msg = tap_graph.getElementsByClassName ('pk_obj2'); + var tap_msg2 = tap_area.getElementsByTagName('span')[0]; + + var bpm_el = value_els[ 0 ]; + var bpm_el_round = value_els[ 1 ]; + var bpm_el_count = value_els[ 2 ]; + var reset_wait = 3000; + + var time_msec = 0; + var time_msec_prev = 0; + var time_msec_first = 0; + var count = 0; + var bpm = 0; + var steps_count = 0; + var first = true; + var is_playing = false; + + var _reset_count = function ( force ) { + if (first) { + tap_msg[1].style.opacity = '0'; + } + + count = 0; + steps_count = 0; + first = true; + + setTimeout(function() { + if (!first) return ; + + tap_msg[0].style.opacity = '0.5'; + if (!force) { + reset_btn.className += ' pk_act'; + setTimeout(function() { + reset_btn.classList.remove ('pk_act'); + },140); + } + + setTimeout(function() { + if (first) { + tap_msg[0].style.opacity = '0'; + tap_msg[1].style.opacity = '0.5'; + } else { + tap_msg[0].style.opacity = '0'; + tap_msg[1].style.opacity = '0'; + } + }, force ? 490 : 874); + }, (force ? 0 : 150)); + + if (force) + { + bpm_el.value = '-'; + bpm_el_round.value = '-'; + bpm_el_count.value = '-'; + + var els = tap_graph.parentNode.getElementsByClassName('pk_obj'); + var l = els.length; + + while (l-- > 0) { + if (els[l]) { + els[l].parentNode.removeChild (els[l]); + } + } + } + }; + + reset_btn.onclick = function () { + _reset_count (true); + }; + + play_btn.onclick = function () { + if (PKAudioEditor.engine.wavesurfer.isPlaying()) { + q.app.fireEvent ('RequestStop'); + } + else { + q.app.fireEvent ('RequestPlay'); + } + }; + + if (!PKAudioEditor.engine.wavesurfer.isReady) + { + play_btn.className += ' pk_inact'; + loop_btn.className += ' pk_inact'; + } + if (PKAudioEditor.engine.wavesurfer.isPlaying()) { + play_btn.className += ' pk_act'; + } + + DidStopPlay = function() { + is_playing = false; + play_btn.classList.remove ('pk_act'); + play_btn.innerText = 'Play Track'; + }; + DidPlay = function() { + is_playing = true; + play_btn.classList.add ('pk_act'); + play_btn.innerText = 'Stop Track'; + }; + + q.app.listenFor ('DidStopPlay', DidStopPlay); + q.app.listenFor ('DidPlay', DidPlay); + + var old_left_time = -999999; + var old_right_time = -999999; + var peaks = []; + var skipp = false; + var remaining = 0; + + DidAudioProcess = function() { + //if (skipp) { + // skipp = false; + // return ; + //} + //skipp = true; + + var wv = PKAudioEditor.engine.wavesurfer; + var buffer = wv.backend.buffer; + var chan_data = buffer.getChannelData ( 0 ); + var sample_rate = buffer.sampleRate; + + var curr_time = wv.getCurrentTime (); + var width = 500; + var height = 100; + var half_height = (height / 2) * 2; + var new_width = width; + var cached_index = 0; + var pixels = 0; + var raw_pixels = 0; + var limit = 3; + + var left_time = curr_time - (limit/2); + var right_time = curr_time + (limit/2); + var quick_render = false; + + var start_offset = (left_time * sample_rate) >> 0; + var end_offset = ((left_time + limit) * sample_rate) >> 0; + var length = end_offset - start_offset; + var mod = (length / width) >> 0; + + if (left_time < old_right_time) + { + // find pixels + var diff = right_time - old_right_time; + // pixels = Math.round ( (diff / limit) * width); + + raw_pixels = ( (diff / limit) * width); + pixels = Math.round ( raw_pixels ); + + raw_pixels = ((raw_pixels*1000) >> 0)/1000; + + if (pixels >= 0) { + if (pixels === 0) return ; + + new_width = pixels; + + start_offset = (old_right_time * sample_rate) >> 0; + end_offset = (right_time * sample_rate) >> 0; + length = end_offset - start_offset; + mod = (length / pixels) >> 0; + + peaks = peaks.slice (pixels * 2); + cached_index = width - pixels; + + quick_render = true; + } + } + + old_right_time = right_time; + + var max = 0; + var min = 0; + + for (var i = 0; i < new_width; ++i) { + var new_offset = start_offset + (mod * i); + + max = 0; + min = 0; + + if (new_offset >= 0) + { + for (var j = 0; j < mod; j += 3) { + if ( chan_data[ new_offset + j] > max ) { + max = chan_data[ new_offset + j]; + } + else if ( chan_data[ new_offset + j] < min ) { + min = chan_data[ new_offset + j]; + } + } + } + + peaks[2 * (i + cached_index)] = max; + peaks[2 * (i + cached_index) + 1 ] = min; + } + + if (quick_render) + { + // var imgdata = ctx.getImageData(0, 0, width, height); + // tempCtx.putImageData (imgdata, 0, 0); + tempCtx.drawImage (canvas, 0, 0); //, width, height, 0, 0, width, height); + } + + ctx.fillStyle = "#000"; + // ctx.clearRect( 0, 0, width, height ); + ctx.fillRect ( 0, 0, width * 2, height * 2 ); + ctx.fillStyle = '#99c2c6'; + + if (quick_render) + { + var forward = Math.round (raw_pixels * 2); + remaining += forward - raw_pixels * 2; + if (remaining > 1) { + forward -= 1; + remaining = 0; + } + + // ctx.translate(-1.5, 0); + ctx.translate (-forward, 0); + ctx.drawImage (tempCanvas, 0, 0); //, width, height, 0, 0, width, height); + ctx.setTransform (1, 0, 0, 1, 0, 0); + +// ctx.drawImage (tempCanvas, 0, 0, width, 100, -(raw_pixels.toFixed(1)/1), 0, width, 100); + + + ctx.beginPath (); + + var peak = peaks[ (width - pixels - 2) * 2]; + var _h = Math.round (peak * half_height); + ctx.moveTo ( (width - pixels - 2) * 2, half_height - _h); + + for (var i = (width - pixels - 1); i < width; ++i) { + peak = peaks[i * 2]; + _h = Math.round (peak * half_height); + ctx.lineTo ( i* 2, half_height - _h); + } + + for (var i = width - 1; i >= (width - pixels - 1); --i) { + var peak = peaks[ (i * 2) + 1]; + var _h = Math.round (peak * half_height); + ctx.lineTo ( i* 2, half_height - _h); + } + + ctx.closePath(); + ctx.fill(); + } + else + { + ctx.beginPath (); + ctx.moveTo ( 0, half_height ); + + for (var i = 0; i < width; ++i) { + var peak = peaks[i * 2]; + var _h = Math.round (peak * half_height); + ctx.lineTo ( i * 2, half_height - _h); + } + + for (var i = width - 1; i >= 0; --i) { + var peak = peaks[ (i * 2) + 1]; + var _h = Math.round (peak * half_height); + ctx.lineTo ( i * 2, half_height - _h); + } + + ctx.closePath(); + ctx.fill(); + } + + //console.log( peaks ); + + }; + + q.app.listenFor ('DidAudioProcess', DidAudioProcess); + + if (PKAudioEditor.engine.wavesurfer.regions.list[0]) + { + if (PKAudioEditor.engine.wavesurfer.regions.list[0].loop) + loop_btn.className += ' pk_act'; + } + loop_btn.onclick = function() { + q.app.fireEvent('RequestSetLoop'); + }; + + DidSetLoop = function( val ) { + val ? loop_btn.classList.add('pk_act') : + loop_btn.classList.remove('pk_act'); + }; + q.app.listenFor('DidSetLoop', DidSetLoop); + + tap_graph.parentNode.addEventListener ('transitionend', function ( e ) { + if (!tap_graph) return ; + + var el = e.target; + if (el.tagName !== 'DIV') return ; + + el.parentNode.removeChild ( el ); + --steps_count; + + if (steps_count === 0) { + + if (is_playing) + setTimeout(function() { + if (steps_count === 0) + _reset_count (); + },1100); + else + _reset_count (); + } + }); + + tap_area.onclick = function ( ev ) { + if (ev) { + ev.preventDefault (); + ev.stopPropagation (); + } + + if (first) { + first = false; + tap_msg[1].style.opacity = '0'; + } + + time_msec = Date.now (); + + if ((time_msec - time_msec_prev) > reset_wait) { + count = 0; + } + + if (count === 0) + { + time_msec_first = time_msec; + count = 1; + + bpm_el.value = 'First Beat'; + bpm_el_round.value = 'First Beat'; + bpm_el_count.value = count; + } + else + { + bpm = 60000 * count / (time_msec - time_msec_first); + ++count; + + bpm_el.value = Math.round (bpm * 100) / 100; + bpm_el_round.value = Math.round (bpm); + bpm_el_count.value = count; + } + + var step = document.createElement ('div'); + step.className = 'pk_obj'; + + if (is_playing) { + canvas.parentNode.appendChild (step); + } + else { + tap_graph.appendChild (step); + } + ++steps_count; + + tap_area.classList.add ('pk_act'); + + requestAnimationFrame(function() { + step.style.transform = 'translate3d(-10%,0,0)'; + + setTimeout(function() { + tap_area.classList.remove ('pk_act'); + },56); + }); + + time_msec_prev = time_msec; + }; + + app.ui.KeyHandler.addCallback ('tmpTap', function ( e, o, ev ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + + ev.preventDefault (); + ev.stopPropagation (); + + tap_area.onclick (null); + }, [32]); + + // --- + }; + }; + + + // events + var TempoEstimation = function ( app, modal ) { + var q = this; + q.app = app; + + q.Init = function ( container ) { + var q = this; + + q.el = container; + + _make_ui ( q ); + _make_evs ( q ); + }; + + q.Destroy = function () { + if (q.body) { + q.body.parentNode.removeChild ( q.body ); + q.body = null; + } + + q.app = null; + }; + + q.Est = function ( selection ) { + var q = this; + + var wavesurfer = q.app.engine.wavesurfer; + var buffer = wavesurfer.backend.buffer; + + var starting_time = 20.375; + var ending_time = wavesurfer.getDuration (); + var sample_rate = buffer.sampleRate; + + var look_ahead = 10 * sample_rate; + var offset_rate = starting_time * sample_rate; + var duration_rate = ending_time * sample_rate; + var dist_rhythm = {}; + + // now run offline + var audio_ctx = getOfflineAudioContext ( + 1, + buffer.sampleRate, + buffer.length + ); + + var source = audio_ctx.createBufferSource (); + source.buffer = buffer; + + var filter = audio_ctx.createBiquadFilter (); + filter.type = 'highpass'; + filter.frequency.value = 50; + filter.Q.value = 1.1; + source.connect (filter); + + var filter2 = audio_ctx.createBiquadFilter (); + filter2.type = 'lowpass'; + filter2.frequency.value = 140; + filter2.Q.value = 2.5; + filter.connect (filter2); + filter2.connect (audio_ctx.destination); + + source.start (0); + + var offline_callback = function( rendered_buffer ) { + _pass ( rendered_buffer, offset_rate, duration_rate ); + }; + + var _pass = function ( rendered_buffer, offset, duration ) { + + var chan_data = rendered_buffer.getChannelData ( 0 ); + var new_arr = []; + var diff_arr = []; + var currval = 0; + var prev_val = 0; + var bottom = 100000; + var top = -100000; + var found_pick = false; + var going_up = false; + var peak_dist = 0; + var peak_prev = 0; + var next_offset = offset + look_ahead; + + var trimmed_arr = []; + var modulus_coefficient = Math.round (look_ahead / 200); + var plus_one = look_ahead + modulus_coefficient; + + for (var i = 0; i < plus_one; ++i) { + if (i % modulus_coefficient === 0) { + + // look into 50 neighboring entries for higher values. + var val_clean = chan_data[ offset + i ]; + var val = Math.abs (val_clean); + + //console.log( "was ", val_clean ); + + var tmp_val = 0; + for (var uu = 1; uu < 50; ++uu) { + tmp_val = Math.abs (chan_data[ offset + i - uu ]); + + if (tmp_val > val) { + val_clean = chan_data[ offset + i - uu ]; + val = Math.abs (val_clean); + } + } + + for (var uu = 1; uu < 50; ++uu) { + tmp_val = Math.abs (chan_data[ offset + i + uu ]); + + if (tmp_val > val) { + val_clean = chan_data[ offset + i + uu ]; + val = Math.abs (val_clean); + } + } + + //console.log( "added ", val_clean ); + //console.log("-----"); + + trimmed_arr.push ( val_clean ); + } + } + + trimmed_arr = _normalize_array2 (trimmed_arr); + trimmed_arr.pop (); + + // ------------ + prev_val = trimmed_arr[0]; + for (var j = 1; j < trimmed_arr.length; ++j) { + currval = trimmed_arr[j]; + + if (currval > prev_val) { + + if (!going_up) { + if (bottom > prev_val) { + bottom = prev_val; + top = -100000; + } + } + + going_up = true; + } + else if (currval < prev_val ) { + + if (going_up) { + + // console.log (":: peak: ", prev_val.toFixed(2)/1, " bottom: ", bottom.toFixed(2)/1, " diff: ", Math.abs(prev_val-bottom).toFixed(2)/1 ); + + found_pick = true; + + if (peak_dist < 3 && Math.abs (new_arr[peak_prev] - prev_val) < 150) { + // debugger; + + if (prev_val > new_arr[peak_prev]) { + new_arr[peak_prev] = 0; + diff_arr.pop (); + } + else { + found_pick = false; + } + } + + if (found_pick) { + diff_arr.push (Math.abs (prev_val - bottom)); + + peak_dist = 0; + new_arr.push ( prev_val ); + + peak_prev = new_arr.length - 1; + + if (prev_val > top) { + top = prev_val; + bottom = 100000; + } + } + // ----- + } + + going_up = false; + } + + prev_val = currval; + + if (!found_pick) { + new_arr.push ( 0 ); + //console.log( "ZEROED ", new_arr.length - 1 ); + ++peak_dist; + } + else { + found_pick = false; + } + } + + // console.log( trimmed_arr ); + // console.log( new_arr ); + // window.trimmed_arr = trimmed_arr; + // window.new_arr = new_arr; + // window.chan = chan_data; + + // ---- + var ret = _group_rhythm ( new_arr, diff_arr ); + if (!ret) { + console.log ("something weird happened, error 244"); + return ; + } + + var distances = ret[0]; + + // console.log( diff_arr ); + // console.log( ret[1] ); + + for (var k in distances) { + if (!dist_rhythm[ k ]) dist_rhythm[ k ] = 0; + + dist_rhythm[ k ] += distances[ k ]; + } + + + console.log ( distances ); + // console.log( ' ---------------- ' ); + // console.log ('--------- END OF PASS ------- ', offset, ' / ', duration); + + if (next_offset + look_ahead >= duration) { + + // Done... + console.log ( dist_rhythm ); + } else { + // _pass ( rendered_buffer, next_offset, duration ); + } + // ---- + }; + + + var offline_renderer = audio_ctx.startRendering(); + if (offline_renderer) + offline_renderer.then( offline_callback ).catch(function(err) { + console.log('Rendering failed: ' + err); + }); + else + audio_ctx.oncomplete = function ( e ) { + offline_callback ( e.renderedBuffer ); + }; + }; + + function _make_ui ( q ) { + var el_drawer = d.createElement ('div'); + el_drawer.className = 'pk_row'; + + // Estimate tempo for selected area button + el_drawer.innerHTML = '
' + + ''+ + ''+ + ''+ + '
' + + '
' + + 'Estimate'+ + '
'; + + q.body = el_drawer; + q.el.appendChild ( el_drawer ); + }; + + function _make_evs ( q ) { + var btn_est = q.body.getElementsByTagName ('a')[0]; + if (!btn_est) return ; + + btn_est.onclick = function () { + q.Est && q.Est (1); + // q.app && q.app.fireEvent ('ReqEst', 1); + }; + }; + }; + + var x = new PKAudioFXModal ({ + id: filter_id, + title: 'Tempo & Rhythm Tools', + + ondestroy: function ( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback (modal_esc_key); + act_tool.Destroy (); + act_tool = null; + + app.fireEvent ('RequestStop'); + }, + + body: '', + +// buttons: [{ +// title:'Apply EQ', +// clss:'pk_modal_a_accpt', +// callback: function( q ) { +// q.Destroy (); +// } +// }], + + setup:function( q ) { + var toplinks = q.el_body.getElementsByClassName('pk_tbsa'); + + var destroy = function () { + if (act_tool) { + act_tool.Destroy (); + act_tool = null; + toplinks[act_index].classList.remove('pk_act'); + } + }; + + var activate = function () { + // get the active state + if (act_index === 0) { + // toplinks[0].className += ' pk_act'; + // act_tool = new TempoEstimation ( app, q ); + return ; + } + else if (act_index === 1) { + toplinks[1].className += ' pk_act'; + act_tool = new TempoTap ( app, q ); + } + else if (act_index === 2) { + toplinks[2].className += ' pk_act'; + act_tool = new TempoMetro ( app, q ); + } + + act_tool && act_tool.Init ( q.el_body ); + }; + + //toplinks[0].onclick = function() { + // destroy (); + // act_index = 0; + // activate (); + //}; + toplinks[1].onclick = function() { + if (act_index === 1) return ; + + destroy (); act_index = 1; + activate (); + }; + toplinks[2].onclick = function() { + if (act_index === 2) return ; + + destroy (); act_index = 2; + activate (); + }; + + activate (); + + // --- + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet (modal_name); + app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + q.Destroy (); + }, [27]); + } + }, app); + + x.Show (); + // ------ + }; + + + PKAudioEditor._deps.FxTMP = TempoToolsModal; + + + /////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + var RecModal = function ( app ) { + var filter_id = 'rec_tools'; + + var audio_stream = null; + var audio_context = null; + var script_processor = null; + var media_stream_source = null; + var temp_buffers = [] + var newbuff = null; + var sample_rate = 44100; + var buffer_size = 2048; // * 2 ? + var channel_num = 1; + var channel_num_out = 1; + + var stop_audio = function () { + if (!audio_stream) return ; + + audio_stream.getTracks().forEach(function (stream) { + stream.stop (); + }); + + if (script_processor) { + script_processor.onaudioprocess = null; + } + media_stream_source && media_stream_source.disconnect (); + script_processor && script_processor.disconnect (); + media_stream_source = null; + audio_stream = null; audio_context = null; + }; + + var x = new PKAudioFXModal ({ + id: filter_id, + title: 'New Recording', + + ondestroy: function ( q ) { + // destroy audio... + stop_audio (); + + temp_buffers = []; + newbuff = null; + + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback (modal_esc_key); + + app.fireEvent ('RequestStop'); + }, + + body: '
' + + '
' + + '' + + '' + + '
' + + '
' + + + '
' + + '
' + + + '
' + + '0.0
' + + '
' + + '
'+ + '
' + + '
' + + 'START RECORDING' + + 'PAUSE' + + '
' + + '' + + '
', + +// buttons: [{ +// title:'Apply EQ', +// clss:'pk_modal_a_accpt', +// callback: function( q ) { +// q.Destroy (); +// } +// }], + + setup:function( q ) { + var is_ready = false; + var is_active = false; + var is_paused = false; + var has_recorded = false; + + var mainbtns = q.el_body.getElementsByClassName('pk_tbsa'); + var btn_start = mainbtns[0]; + var btn_pause = mainbtns[1]; + var btn_open = mainbtns[2]; + var btn_add = mainbtns[3]; + var time_span = q.el_body.getElementsByTagName('span')[0]; + var devices_sel = q.el_body.getElementsByTagName('select')[0]; + var devices = []; + var volcanvas = q.el_body.getElementsByTagName('canvas')[0]; + var volctx = volcanvas.getContext('2d', {alpha:false,antialias:false}); + + var freqcanvas = q.el_body.getElementsByTagName('canvas')[1]; + var freqctx = freqcanvas.getContext('2d', {alpha:false,antialias:false}); + var tempCanvas = document.createElement('canvas'); + tempCanvas.width = 500 * 2; + tempCanvas.height = 100 * 2; + var tempCtx = tempCanvas.getContext ('2d', {alpha:false,antialias:false}); + + + var first_skip = 12; + var curr_offset = 0; + var temp_buffer_index = -1; + var volume = 0; + var currtime = 0; + var has_devices = false; + + var old_left_time = -999999; + var old_right_time = -999999; + var peaks = []; + var skipp = false; + var remaining = 0; + var debounce = false; + + temp_buffers = []; + newbuff = null; + + var draw_volume = function () { + volctx.fillStyle = "#000"; + volctx.fillRect(0,0,200,40); + + if (!is_active) { + return ; + } + + volctx.fillStyle = "green"; + volctx.fillRect(0, 0, volume*200*1.67, 40); + + time_span.innerText = ((currtime * 10) >> 0) / 10; + + window.requestAnimationFrame( draw_volume ); + }; + + var fetchBufferFunction = function (ev) { + if (first_skip > 0) { + --first_skip; + return ; + } + + if (is_paused) { + return ; + } + + curr_offset += ev.inputBuffer.duration * sample_rate; + var float_array = ev.inputBuffer.getChannelData (0).slice (0); + temp_buffers[ ++temp_buffer_index ] = float_array; + + var sum = 0; + var x; + + for (var i = 0; i < buffer_size; i += 2) { + x = float_array[i]; + sum += x * x; + } + + var rms = Math.sqrt(sum / (buffer_size / 2) ); + volume = Math.max(rms, volume * 0.9); + + + var curr_time = (temp_buffer_index * buffer_size) / sample_rate; + currtime = curr_time; + var width = 500; + var height = 100; + var half_height = (height / 2) * 2; + var new_width = width; + var cached_index = 0; + var pixels = 0; + var raw_pixels = 0; + var limit = 3; + + var left_time = curr_time - limit; + var right_time = curr_time; // + (limit/2); + var quick_render = false; + + var start_offset = (left_time * sample_rate) >> 0; + var end_offset = ((left_time + limit) * sample_rate) >> 0; + var length = end_offset - start_offset; + var mod = (length / width) >> 0; + + if (left_time < old_right_time) + { + // find pixels + var diff = right_time - old_right_time; + // pixels = Math.round ( (diff / limit) * width); + + raw_pixels = ( (diff / limit) * width); + pixels = Math.round ( raw_pixels ); + + raw_pixels = ((raw_pixels*1000) >> 0)/1000; + + if (pixels >= 0) { + if (pixels === 0) return ; + + new_width = pixels; + + start_offset = (old_right_time * sample_rate) >> 0; + end_offset = (right_time * sample_rate) >> 0; + length = end_offset - start_offset; + mod = (length / pixels) >> 0; + + peaks = peaks.slice (pixels * 2); + cached_index = width - pixels; + + quick_render = true; + } + } + + old_right_time = right_time; + + var max = 0; + var min = 0; + + for (var i = 0; i < new_width; ++i) + { + var new_offset = start_offset + (mod * i); + + max = 0; + min = 0; + + if (new_offset >= 0) + { + for (var j = 0; j < mod; j += 3) { + var temp = new_offset + j; + var temp2 = (temp/2048) >> 0; + var temp3 = temp % 2048; + + if (!temp_buffers[temp2]) continue; + + if ( temp_buffers[temp2][ temp3 ] > max ) { + max = temp_buffers[temp2][ temp3 ]; + } + else if ( temp_buffers[temp2][ temp3 ] < min ) { + min = temp_buffers[temp2][ temp3 ]; + } + } + } + + peaks[2 * (i + cached_index)] = max; + peaks[2 * (i + cached_index) + 1 ] = min; + } + + if (quick_render) + { + // var imgdata = ctx.getImageData(0, 0, width, height); + // tempCtx.putImageData (imgdata, 0, 0); + tempCtx.drawImage (freqcanvas, 0, 0); //, width, height, 0, 0, width, height); + } + + freqctx.fillStyle = "#000"; + // freqctx.clearRect( 0, 0, width, height ); + freqctx.fillRect ( 0, 0, width * 2, height * 2 ); + freqctx.fillStyle = '#99c2c6'; + + if (quick_render) + { + var forward = Math.round (raw_pixels * 2); + remaining += forward - raw_pixels * 2; + if (remaining > 1) { + forward -= 1; + remaining = 0; + } + + // freqctx.translate(-1.5, 0); + freqctx.translate (-forward, 0); + freqctx.drawImage (tempCanvas, 0, 0); //, width, height, 0, 0, width, height); + freqctx.setTransform (1, 0, 0, 1, 0, 0); + + // freqctx.drawImage (tempCanvas, 0, 0, width, 100, -(raw_pixels.toFixed(1)/1), 0, width, 100); + + + freqctx.beginPath (); + + var peak = peaks[ (width - pixels - 2) * 2]; + var _h = Math.round (peak * half_height); + freqctx.moveTo ( (width - pixels - 2) * 2, half_height - _h); + + for (var i = (width - pixels - 1); i < width; ++i) { + peak = peaks[i * 2]; + _h = Math.round (peak * half_height); + freqctx.lineTo ( i* 2, half_height - _h); + } + + for (var i = width - 1; i >= (width - pixels - 1); --i) { + var peak = peaks[ (i * 2) + 1]; + var _h = Math.round (peak * half_height); + freqctx.lineTo ( i* 2, half_height - _h); + } + + freqctx.closePath(); + freqctx.fill(); + } + else + { + freqctx.beginPath (); + freqctx.moveTo ( 0, half_height ); + + for (var i = 0; i < width; ++i) { + var peak = peaks[i * 2]; + var _h = Math.round (peak * half_height); + freqctx.lineTo ( i * 2, half_height - _h); + } + + for (var i = width - 1; i >= 0; --i) { + var peak = peaks[ (i * 2) + 1]; + var _h = Math.round (peak * half_height); + freqctx.lineTo ( i * 2, half_height - _h); + } + + freqctx.closePath(); + freqctx.fill(); + } + + }; + + navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(function( _stream ) { + _stream.getTracks().forEach(function (stream) { + stream.stop (); + }); + + enumerate (); + }).catch(function(error) { + alert("no microphone permissions found!"); + }); + + var enumerate = function () { + if (navigator.mediaDevices.enumerateDevices) { + navigator.mediaDevices.enumerateDevices().then((devices) => { + devices = devices.filter((d) => d.kind === 'audioinput'); + has_devices = true; + + var len = devices.length; + for (var i = 0; i < len; ++i) { + var el = document.createElement('option'); + el.value = devices[i].deviceId; + el.innerText = devices[i].label; + devices_sel.appendChild (el); + } + + is_ready = true; + btn_start.classList.remove ('pk_inact'); + }); + } + else { + devices_sel.parentNode.style.display = 'none'; + has_devices = false; + is_ready = true; + btn_start.classList.remove ('pk_inact'); + } + }; + + var stop = function () { + stop_audio (); + + is_active = false; + is_paused = false; + first_skip = 10; + + ++temp_buffer_index; + var k = -1; + newbuff = new Float32Array (temp_buffer_index * buffer_size); + for (var i = 0; i < temp_buffer_index; ++i) + { + for (var j = 0; j < buffer_size; ++j) + { + newbuff[++k] = temp_buffers[i][j]; + } + } + + temp_buffer_index = -1; + temp_buffers = []; + + // ------ + btn_open.style.display = 'block'; + + // check to see if we are ready + if (app.engine.is_ready) { + btn_add.style.display = 'block'; + } + + has_recorded = true; + }; + // --- + + btn_start.onclick = function () { + if (!is_ready) return ; + + if (debounce) { + return ; + } + + debounce = true; + setTimeout(function() { + debounce = false; + }, 260); + + // check if recording exists - ask for confirmation + if (has_recorded) { + if (!window.confirm("Are you sure? This will discard the current recording.")) + { + return ; + } + } + + + if (is_active) { + stop (); + + btn_pause.classList.add ('pk_inact'); + btn_start.innerText = 'START RECORDING'; + btn_start.style.boxShadow = 'none'; + + return ; + } + + temp_buffer_index = -1; + temp_buffers = []; + newbuff = null; + volume = 0; + + btn_open.style.display = 'none'; + btn_add.style.display = 'none'; + + audio_context = new (window.AudioContext || window.webkitAudioContext)(); + sample_rate = audio_context.sampleRate; + + var audio_val = true; + if (has_devices) { + audio_val = {deviceId: devices_sel.value}; + // devices_sel.options[devices_sel.selectedIndex].value; + } + + navigator.mediaDevices.getUserMedia({ audio: audio_val }).then(function( stream ) { + audio_stream = stream; + media_stream_source = audio_context.createMediaStreamSource ( stream ); + + script_processor = audio_context.createScriptProcessor ( + buffer_size, channel_num, channel_num_out + ); + + media_stream_source.connect ( script_processor ); + script_processor.connect ( audio_context.destination ); + + is_active = true; + btn_pause.classList.remove ('pk_inact'); + btn_start.innerText = 'FINISH RECORDING'; + btn_start.style.boxShadow = '#992222 0px 0px 6px inset'; + script_processor.onaudioprocess = fetchBufferFunction; + + draw_volume (); + + }).catch(function(error) { + + }); + + }; + + btn_pause.onclick = function () { + if (!is_ready) return ; + if (!is_active) return ; + + is_paused = !is_paused; + + btn_pause.innerText = is_paused ? 'UN-PAUSE' : 'PAUSE'; + }; + + btn_open.onclick = function () { + if (debounce) { + return ; + } + + debounce = true; + setTimeout(function() { + debounce = false; + }, 150); + + app.engine.wavesurfer.backend._add = 0; + app.engine.LoadDB ({ + samplerate: sample_rate, + data: [ + newbuff.buffer + ] + }); + + // ---- + q.Destroy (); + }; + + btn_add.onclick = function () { + if (debounce) { + return ; + } + + debounce = true; + setTimeout(function() { + debounce = false; + }, 150); + + app.engine.wavesurfer.backend._add = 1; + app.engine.LoadDB ({ + samplerate: sample_rate, + data: [ + newbuff.buffer + ] + }); + + // ---- + q.Destroy (); + }; + + // --- + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet (modal_name); + app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + q.Destroy (); + }, [27]); + } + }, app); + + x.Show (); + }; + + PKAudioEditor._deps.FxREC = RecModal; + +})( window, document, PKAudioEditor ); \ No newline at end of file diff --git a/audiomass-editor/src/ico.png b/audiomass-editor/src/ico.png new file mode 100644 index 0000000..a3ec65a Binary files /dev/null and b/audiomass-editor/src/ico.png differ diff --git a/audiomass-editor/src/icon.png b/audiomass-editor/src/icon.png new file mode 100644 index 0000000..a123a6a Binary files /dev/null and b/audiomass-editor/src/icon.png differ diff --git a/audiomass-editor/src/id3.js b/audiomass-editor/src/id3.js new file mode 100644 index 0000000..9a12652 --- /dev/null +++ b/audiomass-editor/src/id3.js @@ -0,0 +1,856 @@ +(function ( w, d, PKAE ) { + 'use strict'; + + + var StringUtils = { + readUTF16String: function(bytes, bigEndian, maxBytes) { + var ix = 0; + var offset1 = 1, offset2 = 0; + maxBytes = Math.min(maxBytes||bytes.length, bytes.length); + + if( bytes[0] == 0xFE && bytes[1] == 0xFF ) { + bigEndian = true; + ix = 2; + } else if( bytes[0] == 0xFF && bytes[1] == 0xFE ) { + bigEndian = false; + ix = 2; + } + if( bigEndian ) { + offset1 = 0; + offset2 = 1; + } + + var arr = []; + for( var j = 0; ix < maxBytes; j++ ) { + var byte1 = bytes[ix+offset1]; + var byte2 = bytes[ix+offset2]; + var word1 = (byte1<<8)+byte2; + ix += 2; + if( word1 == 0x0000 ) { + break; + } else if( byte1 < 0xD8 || byte1 >= 0xE0 ) { + arr[j] = String.fromCharCode(word1); + } else { + var byte3 = bytes[ix+offset1]; + var byte4 = bytes[ix+offset2]; + var word2 = (byte3<<8)+byte4; + ix += 2; + arr[j] = String.fromCharCode(word1, word2); + } + } + var string = new String(arr.join("")); + string.bytesReadCount = ix; + return string; + }, + readUTF8String: function(bytes, maxBytes) { + var ix = 0; + maxBytes = Math.min(maxBytes||bytes.length, bytes.length); + + if( bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF ) { + ix = 3; + } + + var arr = []; + for( var j = 0; ix < maxBytes; j++ ) { + var byte1 = bytes[ix++]; + if( byte1 == 0x00 ) { + break; + } else if( byte1 < 0x80 ) { + arr[j] = String.fromCharCode(byte1); + } else if( byte1 >= 0xC2 && byte1 < 0xE0 ) { + var byte2 = bytes[ix++]; + arr[j] = String.fromCharCode(((byte1&0x1F)<<6) + (byte2&0x3F)); + } else if( byte1 >= 0xE0 && byte1 < 0xF0 ) { + var byte2 = bytes[ix++]; + var byte3 = bytes[ix++]; + arr[j] = String.fromCharCode(((byte1&0xFF)<<12) + ((byte2&0x3F)<<6) + (byte3&0x3F)); + } else if( byte1 >= 0xF0 && byte1 < 0xF5) { + var byte2 = bytes[ix++]; + var byte3 = bytes[ix++]; + var byte4 = bytes[ix++]; + var codepoint = ((byte1&0x07)<<18) + ((byte2&0x3F)<<12)+ ((byte3&0x3F)<<6) + (byte4&0x3F) - 0x10000; + arr[j] = String.fromCharCode( + (codepoint>>10) + 0xD800, + (codepoint&0x3FF) + 0xDC00 + ); + } + } + var string = new String(arr.join("")); + string.bytesReadCount = ix; + return string; + }, + readNullTerminatedString: function(bytes, maxBytes) { + var arr = []; + maxBytes = maxBytes || bytes.length; + for ( var i = 0; i < maxBytes; ) { + var byte1 = bytes[i++]; + if( byte1 == 0x00 ) break; + arr[i-1] = String.fromCharCode(byte1); + } + var string = new String(arr.join("")); + string.bytesReadCount = i; + return string; + } + }; + + var getBytesAt = function(data, iOffset, iLength) { + var bytes = new Array(iLength); + for( var i = 0; i < iLength; i++ ) { + bytes[i] = data.getUint8(iOffset+i); + } + return bytes; + }; + var getStringWithCharsetAt = function(data, iOffset, iLength, iCharset) { + var bytes = getBytesAt(data, iOffset, iLength); + var sString; + + switch( iCharset.toLowerCase() ) { + case 'utf-16': + case 'utf-16le': + case 'utf-16be': + sString = StringUtils.readUTF16String(bytes, iCharset); + break; + + case 'utf-8': + sString = StringUtils.readUTF8String(bytes); + break; + + default: + sString = StringUtils.readNullTerminatedString(bytes); + break; + } + + return sString; + }; + + var ID3v2 = { + readFrameData: {} + }; + + ID3v2.frames = { + // v2.2 + "BUF" : "Recommended buffer size", + "CNT" : "Play counter", + "COM" : "Comments", + "CRA" : "Audio encryption", + "CRM" : "Encrypted meta frame", + "ETC" : "Event timing codes", + "EQU" : "Equalization", + "GEO" : "General encapsulated object", + "IPL" : "Involved people list", + "LNK" : "Linked information", + "MCI" : "Music CD Identifier", + "MLL" : "MPEG location lookup table", + "PIC" : "Attached picture", + "POP" : "Popularimeter", + "REV" : "Reverb", + "RVA" : "Relative volume adjustment", + "SLT" : "Synchronized lyric/text", + "STC" : "Synced tempo codes", + "TAL" : "Album/Movie/Show title", + "TBP" : "BPM (Beats Per Minute)", + "TCM" : "Composer", + "TCO" : "Content type", + "TCR" : "Copyright message", + "TDA" : "Date", + "TDY" : "Playlist delay", + "TEN" : "Encoded by", + "TFT" : "File type", + "TIM" : "Time", + "TKE" : "Initial key", + "TLA" : "Language(s)", + "TLE" : "Length", + "TMT" : "Media type", + "TOA" : "Original artist(s)/performer(s)", + "TOF" : "Original filename", + "TOL" : "Original Lyricist(s)/text writer(s)", + "TOR" : "Original release year", + "TOT" : "Original album/Movie/Show title", + "TP1" : "Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group", + "TP2" : "Band/Orchestra/Accompaniment", + "TP3" : "Conductor/Performer refinement", + "TP4" : "Interpreted, remixed, or otherwise modified by", + "TPA" : "Part of a set", + "TPB" : "Publisher", + "TRC" : "ISRC (International Standard Recording Code)", + "TRD" : "Recording dates", + "TRK" : "Track number/Position in set", + "TSI" : "Size", + "TSS" : "Software/hardware and settings used for encoding", + "TT1" : "Content group description", + "TT2" : "Title/Songname/Content description", + "TT3" : "Subtitle/Description refinement", + "TXT" : "Lyricist/text writer", + "TXX" : "User defined text information frame", + "TYE" : "Year", + "UFI" : "Unique file identifier", + "ULT" : "Unsychronized lyric/text transcription", + "WAF" : "Official audio file webpage", + "WAR" : "Official artist/performer webpage", + "WAS" : "Official audio source webpage", + "WCM" : "Commercial information", + "WCP" : "Copyright/Legal information", + "WPB" : "Publishers official webpage", + "WXX" : "User defined URL link frame", + // v2.3 + "AENC" : "Audio encryption", + "APIC" : "Attached picture", + "COMM" : "Comments", + "COMR" : "Commercial frame", + "ENCR" : "Encryption method registration", + "EQUA" : "Equalization", + "ETCO" : "Event timing codes", + "GEOB" : "General encapsulated object", + "GRID" : "Group identification registration", + "IPLS" : "Involved people list", + "LINK" : "Linked information", + "MCDI" : "Music CD identifier", + "MLLT" : "MPEG location lookup table", + "OWNE" : "Ownership frame", + "PRIV" : "Private frame", + "PCNT" : "Play counter", + "POPM" : "Popularimeter", + "POSS" : "Position synchronisation frame", + "RBUF" : "Recommended buffer size", + "RVAD" : "Relative volume adjustment", + "RVRB" : "Reverb", + "SYLT" : "Synchronized lyric/text", + "SYTC" : "Synchronized tempo codes", + "TALB" : "Album/Movie/Show title", + "TBPM" : "BPM (beats per minute)", + "TCOM" : "Composer", + "TCON" : "Content type", + "TCOP" : "Copyright message", + "TDAT" : "Date", + "TDLY" : "Playlist delay", + "TENC" : "Encoded by", + "TEXT" : "Lyricist/Text writer", + "TFLT" : "File type", + "TIME" : "Time", + "TIT1" : "Content group description", + "TIT2" : "Title/songname/content description", + "TIT3" : "Subtitle/Description refinement", + "TKEY" : "Initial key", + "TLAN" : "Language(s)", + "TLEN" : "Length", + "TMED" : "Media type", + "TOAL" : "Original album/movie/show title", + "TOFN" : "Original filename", + "TOLY" : "Original lyricist(s)/text writer(s)", + "TOPE" : "Original artist(s)/performer(s)", + "TORY" : "Original release year", + "TOWN" : "File owner/licensee", + "TPE1" : "Lead performer(s)/Soloist(s)", + "TPE2" : "Band/orchestra/accompaniment", + "TPE3" : "Conductor/performer refinement", + "TPE4" : "Interpreted, remixed, or otherwise modified by", + "TPOS" : "Part of a set", + "TPUB" : "Publisher", + "TRCK" : "Track number/Position in set", + "TRDA" : "Recording dates", + "TRSN" : "Internet radio station name", + "TRSO" : "Internet radio station owner", + "TSIZ" : "Size", + "TSRC" : "ISRC (international standard recording code)", + "TSSE" : "Software/Hardware and settings used for encoding", + "TYER" : "Year", + "TXXX" : "User defined text information frame", + "UFID" : "Unique file identifier", + "USER" : "Terms of use", + "USLT" : "Unsychronized lyric/text transcription", + "WCOM" : "Commercial information", + "WCOP" : "Copyright/Legal information", + "WOAF" : "Official audio file webpage", + "WOAR" : "Official artist/performer webpage", + "WOAS" : "Official audio source webpage", + "WORS" : "Official internet radio station homepage", + "WPAY" : "Payment", + "WPUB" : "Publishers official webpage", + "WXXX" : "User defined URL link frame" + }; + + var pictureType = [ + "32x32 pixels 'file icon' (PNG only)", + "Other file icon", + "Cover (front)", + "Cover (back)", + "Leaflet page", + "Media (e.g. lable side of CD)", + "Lead artist/lead performer/soloist", + "Artist/performer", + "Conductor", + "Band/Orchestra", + "Composer", + "Lyricist/text writer", + "Recording Location", + "During recording", + "During performance", + "Movie/video screen capture", + "A bright coloured fish", + "Illustration", + "Band/artist logotype", + "Publisher/Studio logotype" + ]; + + var getStringAt = function(data, iOffset, iLength) { + var aStr = []; + for (var i=iOffset,j=0;i 2147483647) + return iULong - 4294967296; + else + return iULong; + }; + var getShortAt = function(data, iOffset, bBigEndian) { + var iShort = bBigEndian ? + (data.getUint8(iOffset) << 8) + data.getUint8(iOffset + 1) + : (data.getUint8(iOffset + 1) << 8) + data.getUint8(iOffset); + if (iShort < 0) iShort += 65536; + return iShort; + }; + var getInteger24At = function(data, iOffset, bBigEndian) { + var iByte1 = data.getUint8(iOffset), + iByte2 = data.getUint8(iOffset + 1), + iByte3 = data.getUint8(iOffset + 2); + + var iInteger = bBigEndian ? + ((((iByte1 << 8) + iByte2) << 8) + iByte3) + : ((((iByte3 << 8) + iByte2) << 8) + iByte1); + if (iInteger < 0) iInteger += 16777216; + return iInteger; + }; + var isBitSetAt = function ( dataview, offset, bit ) { + var ibyte = dataview.getUint8(offset); + return (ibyte & (1 << bit)) != 0; + }; + var readSynchsafeInteger32At = function (offset, data) { + var size1 = data.getUint8(offset); + var size2 = data.getUint8(offset+1); + var size3 = data.getUint8(offset+2); + var size4 = data.getUint8(offset+3); + // 0x7f = 0b01111111 + var size = size4 & 0x7f + | ((size3 & 0x7f) << 7) + | ((size2 & 0x7f) << 14) + | ((size1 & 0x7f) << 21); + + return size; + }; + var readFrameFlags = function(data, offset) { + var flags = + { + message: + { + tag_alter_preservation : isBitSetAt(data, offset, 6), + file_alter_preservation : isBitSetAt(data, offset, 5), + read_only : isBitSetAt(data, offset, 4) + }, + format: + { + grouping_identity : isBitSetAt(data, offset+1, 7), + compression : isBitSetAt(data, offset+1, 3), + encription : isBitSetAt(data, offset+1, 2), + unsynchronisation : isBitSetAt(data, offset+1, 1), + data_length_indicator : isBitSetAt(data, offset+1, 0) + } + }; + + return flags; + }; + var _shortcuts = { + "title" : ["TIT2", "TT2"], + "artist" : ["TPE1", "TP1"], + "album" : ["TALB", "TAL"], + "year" : ["TYER", "TYE"], + "comment" : ["COMM", "COM"], + "track" : ["TRCK", "TRK"], + "genre" : ["TCON", "TCO"], + "picture" : ["APIC", "PIC"], + "lyrics" : ["USLT", "ULT"] + }; + var _defaultShortcuts = ["title", "artist", "album", "track"]; + + var getTagsFromShortcuts = function(shortcuts) { + var tags = []; + for( var i = 0, shortcut; shortcut = shortcuts[i]; i++ ) { + tags = tags.concat(_shortcuts[shortcut]||[shortcut]); + } + return tags; + }; + var getFrameData = function( frames, ids ) { + if( typeof ids == 'string' ) { ids = [ids]; } + + for( var i = 0, id; id = ids[i]; i++ ) { + if( id in frames ) { return frames[id].data; } + } + }; + var readFrames = function (offset, end, data, id3header, tags) { + var frames = {}; + var frameDataSize; + var major = id3header["major"]; + + tags = getTagsFromShortcuts(tags || _defaultShortcuts); + + while( offset < end ) { + var readFrameFunc = null; + var frameData = data; + var frameDataOffset = offset; + var flags = null; + + switch( major ) { + case 2: + var frameID = getStringAt(frameData, frameDataOffset, 3); + var frameSize = getInteger24At(frameData, frameDataOffset+3, true); + var frameHeaderSize = 6; + break; + + case 3: + var frameID = getStringAt(frameData, frameDataOffset, 4); + var frameSize = getLongAt(frameData, frameDataOffset+4, true); + var frameHeaderSize = 10; + break; + + case 4: + var frameID = getStringAt(frameData, frameDataOffset, 4); + var frameSize = readSynchsafeInteger32At(frameDataOffset+4, frameData); + var frameHeaderSize = 10; + break; + } + // if last frame GTFO + if( frameID == "" ) { break; } + + // advance data offset to the next frame data + offset += frameHeaderSize + frameSize; + // skip unwanted tags + if( tags.indexOf( frameID ) < 0 ) { continue; } + + // read frame message and format flags + if( major > 2 ) + { + flags = readFrameFlags(frameData, frameDataOffset+8); + } + + frameDataOffset += frameHeaderSize; + + // the first 4 bytes are the real data size + // (after unsynchronisation && encryption) + if( flags && flags.format.data_length_indicator ) + { + frameDataSize = readSynchsafeInteger32At(frameDataOffset, frameData); + frameDataOffset += 4; + frameSize -= 4; + } + + // TODO: support unsynchronisation + if( flags && flags.format.unsynchronisation ) + { + //frameData = removeUnsynchronisation(frameData, frameSize); + continue; + } + + // find frame parsing function + + if( frameID in ID3v2.readFrameData ) { + readFrameFunc = ID3v2.readFrameData[frameID]; + } else if( frameID[0] == "T" ) { + readFrameFunc = ID3v2.readFrameData["T*"]; + } + + var parsedData = readFrameFunc ? readFrameFunc(frameDataOffset, frameSize, frameData, flags) : undefined; + var desc = frameID in ID3v2.frames ? ID3v2.frames[frameID] : 'Unknown'; + + var frame = { + id : frameID, + size : frameSize, + description : desc, + data : parsedData + }; + + if( frameID in frames ) { + if( frames[frameID].id ) { + frames[frameID] = [frames[frameID]]; + } + frames[frameID].push(frame); + } else { + frames[frameID] = frame; + } + } + + return frames; + }; + + function getTextEncoding( bite ) { + var charset; + switch( bite ) + { + case 0x00: + charset = 'iso-8859-1'; + break; + + case 0x01: + charset = 'utf-16'; + break; + + case 0x02: + charset = 'utf-16be'; + break; + + case 0x03: + charset = 'utf-8'; + break; + } + + return charset; + } + + function getTime( duration ) + { + var duration = duration/1000, + seconds = Math.floor( duration ) % 60, + minutes = Math.floor( duration/60 ) % 60, + hours = Math.floor( duration/3600 ); + + return { + seconds : seconds, + minutes : minutes, + hours : hours + }; + } + + function formatTime( time ) + { + var seconds = time.seconds < 10 ? '0'+time.seconds : time.seconds; + var minutes = (time.hours > 0 && time.minutes < 10) ? '0'+time.minutes : time.minutes; + + return (time.hours>0?time.hours+':':'') + minutes + ':' + seconds; + } + + ID3v2.readFrameData['APIC'] = function readPictureFrame(offset, length, data, flags, v) { + v = v || '3'; + + var start = offset; + var charset = getTextEncoding( data.getUint8(offset) ); + switch( v ) { + case '2': + var format = getStringAt(data, offset+1, 3); + offset += 4; + break; + + case '3': + case '4': + var format = getStringWithCharsetAt(data, offset+1, length - (offset-start), ''); + offset += 1 + format.bytesReadCount; + break; + } + var bite = data.getUint8(offset, 1); + var type = pictureType[bite]; + var desc = getStringWithCharsetAt(data, offset+1, length - (offset-start), charset); + + offset += 1 + desc.bytesReadCount; + + return { + "format" : format.toString(), + "type" : type, + "description" : desc.toString(), + "data" : getBytesAt(data, offset, (start+length) - offset) + }; + }; + + ID3v2.readFrameData['COMM'] = function readCommentsFrame(offset, length, data) { + var start = offset; + var charset = getTextEncoding( data.getUint8(offset) ); + var language = getStringAt(data, offset+1, 3 ); + var shortdesc = getStringWithCharsetAt(data, offset+4, length-4, charset); + + offset += 4 + shortdesc.bytesReadCount; + var text = getStringWithCharsetAt(data, offset, (start+length) - offset, charset ); + + return { + language : language, + short_description : shortdesc.toString(), + text : text.toString() + }; + }; + + ID3v2.readFrameData['COM'] = ID3v2.readFrameData['COMM']; + + ID3v2.readFrameData['PIC'] = function(offset, length, data, flags) { + return ID3v2.readFrameData['APIC'](offset, length, data, flags, '2'); + }; + + ID3v2.readFrameData['PCNT'] = function readCounterFrame(offset, length, data) { + // FIXME: implement the rest of the spec + return data.getInteger32At(offset); + }; + + ID3v2.readFrameData['CNT'] = ID3v2.readFrameData['PCNT']; + + ID3v2.readFrameData['T*'] = function readTextFrame(offset, length, data) { + var charset = getTextEncoding( data.getUint8(offset) ); + + return getStringWithCharsetAt(data, offset+1, length-1, charset).toString(); + }; + + ID3v2.readFrameData['TCON'] = function readGenreFrame(offset, length, data) { + var text = ID3v2.readFrameData['T*'].apply( this, arguments ); + return text.replace(/^\(\d+\)/, ''); + }; + + ID3v2.readFrameData['TCO'] = ID3v2.readFrameData['TCON']; + + //ID3v2.readFrameData['TLEN'] = function readLengthFrame(offset, length, data) { + // var text = ID3v2.readFrameData['T*'].apply( this, arguments ); + // + // return { + // text : text, + // parsed : formatTime( getTime(parseInt(text)) ) + // }; + //}; + + ID3v2.readFrameData['USLT'] = function readLyricsFrame(offset, length, data) { + var start = offset; + var charset = getTextEncoding( data.getUint8(offset) ); + var language = getStringAt(data, offset+1, 3 ); + var descriptor = getStringWithCharsetAt(data, offset+4, length-4, charset ); + + offset += 4 + descriptor.bytesReadCount; + var lyrics = getStringWithCharsetAt(data, offset, (start+length) - offset, charset ); + + return { + language : language, + descriptor : descriptor.toString(), + lyrics : lyrics.toString() + }; + }; + + ID3v2.readFrameData['ULT'] = ID3v2.readFrameData['USLT']; + + + ID3v2.ReadTags = function ( arraybuffer ) { + var data = new DataView ( arraybuffer ); + var offset = 0; + + + var major = data.getUint8(offset+3); + if( major > 4 ) { return {version: '>2.4'}; } + var revision = data.getUint8(offset+4); + var unsynch = isBitSetAt(data, offset+5, 7); + var xheader = isBitSetAt(data, offset+5, 6); + var xindicator = isBitSetAt(data, offset+5, 5); + var size = readSynchsafeInteger32At(offset+6, data); + offset += 10; + + if( xheader ) { + var xheadersize = data.getInt32( offset, true ); //data.getLongAt(offset, true); + // The 'Extended header size', currently 6 or 10 bytes, excludes itself. + offset += xheadersize + 4; + } + + var id3 = { + "version" : '2.' + major + '.' + revision, + "major" : major, + "revision" : revision, + "flags" : { + "unsynchronisation" : unsynch, + "extended_header" : xheader, + "experimental_indicator" : xindicator + }, + "size" : size + }; + + var frames = unsynch ? {} : readFrames(offset, size-10, data, id3); + // create shortcuts for most common data + for( var name in _shortcuts ) if(_shortcuts.hasOwnProperty(name)) { + var data = getFrameData( frames, _shortcuts[name] ); + if( data ) id3[name] = data; + } + + for( var frame in frames ) { + if( frames.hasOwnProperty(frame) ) { + id3[frame] = frames[frame]; + } + } + + return id3; + }; + + w.ID3v2 = ID3v2; + + + /// ------- + + var ID4 = {}; + + ID4.types = { + '0' : 'uint8', + '1' : 'text', + '13' : 'jpeg', + '14' : 'png', + '21' : 'uint8' + }; + ID4.atom = { + '©alb': ['album'], + '©art': ['artist'], + '©ART': ['artist'], + 'aART': ['artist'], + '©day': ['year'], + '©nam': ['title'], + '©gen': ['genre'], + 'trkn': ['track'], + '©wrt': ['composer'], + '©too': ['encoder'], + 'cprt': ['copyright'], + 'covr': ['picture'], + '©grp': ['grouping'], + 'keyw': ['keyword'], + '©lyr': ['lyrics'], + '©cmt': ['comment'], + 'tmpo': ['tempo'], + 'cpil': ['compilation'], + 'disk': ['disc'] + }; + + ID4.loadData = function(arraybuffer, callback) { + var data = new DataView ( arraybuffer ); + // load the header of the first block + loadAtom(data, 0, data.byteLength, callback); + }; + + /** + * Make sure that the [offset, offset+7] bytes (the block header) are + * already loaded before calling this function. + */ + function loadAtom(data, offset, length, callback) { + // 8 is the size of the atomSize and atomName fields. + // When reading the current block we always read 8 more bytes in order + // to also read the header of the next block. + var atomSize = getLongAt(data, offset, true); + if (atomSize == 0) return callback(); + var atomName = getStringAt(data, offset + 4, 4); + + // Container atoms + if (['moov', 'udta', 'meta', 'ilst'].indexOf(atomName) > -1) + { + if (atomName == 'meta') offset += 4; // next_item_id (uint32) + // data.loadRange([offset+8, offset+8 + 8], function() { + loadAtom(data, offset + 8, atomSize - 8, callback); + // }); + } else { + // Value atoms + var readAtom = atomName in ID4.atom; + // data.loadRange([offset+(readAtom?0:atomSize), offset+atomSize + 8], function() { + loadAtom(data, offset+atomSize, length, callback); + // }); + } + }; + + ID4.ReadTags = function(arraybuffer) { + var data = new DataView ( arraybuffer ); + var tag = {}; + readAtom(tag, data, 0, data.byteLength); + return tag; + }; + + function readAtom(tag, data, offset, length, indent) + { + // debugger; + + indent = indent === undefined ? "" : indent + " "; + var seek = offset; + while (seek < offset + length) + { + var atomSize = data.getInt32(seek); // getLongAt(data, seek, true); + if (atomSize == 0) return; + var atomName = getStringAt(data, seek + 4, 4); + // Container atoms + if (atomName === 'meta') + { + seek += 4; // next_item_id (uint32) + readAtom(tag, data, seek + 8, atomSize - 8, indent); + return; + } + if (atomName === 'moov' || atomName === 'udta' || atomName === 'ilst' ) // ['moov', 'udta', 'meta', 'ilst'].indexOf(atomName) > -1) + { + readAtom(tag, data, seek + 8, atomSize - 8, indent); + return; + } + + /* + if (['moov', 'udta', 'meta', 'ilst'].indexOf(atomName) > -1) + { + if (atomName === 'meta') seek += 4; // next_item_id (uint32) + readAtom(tag, data, seek + 8, atomSize - 8, indent); + return; + } + */ + + // Value atoms + if (ID4.atom[atomName]) + { + var klass = getInteger24At(data, seek + 16 + 1, true); + var atom = ID4.atom[atomName]; + var type = ID4.types[klass]; + if (atomName === 'trkn') + { + tag[atom[0]] = data.getUint8(seek + 16 + 11); + tag['count'] = data.getUint8(seek + 16 + 13); + } + else + { + // 16: name + size + "data" + size (4 bytes each) + // 4: atom version (1 byte) + atom flags (3 bytes) + // 4: NULL (usually locale indicator) + var dataStart = seek + 16 + 4 + 4; + var dataEnd = atomSize - 16 - 4 - 4; + var atomData; + switch( type ) { + case 'text': + atomData = getStringWithCharsetAt(data, dataStart, dataEnd, "UTF-8"); + break; + + case 'uint8': + atomData = getShortAt(data, dataStart); + break; + + case 'jpeg': + case 'png': + atomData = { + format : "image/" + type, + data : getBytesAt(data, dataStart, dataEnd) + }; + break; + } + + if (atom[0] === "comment") { + tag[atom[0]] = { + "text": atomData + }; + } else { + tag[atom[0]] = atomData; + } + } + } + seek += atomSize; + } + } + + w.ID4 = ID4; + +})( window, document, PKAudioEditor ); \ No newline at end of file diff --git a/audiomass-editor/src/index-cache.html b/audiomass-editor/src/index-cache.html new file mode 100755 index 0000000..b69183b --- /dev/null +++ b/audiomass-editor/src/index-cache.html @@ -0,0 +1,66 @@ + + + + AudioMass - Audio Editor + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/audiomass-editor/src/index.html b/audiomass-editor/src/index.html new file mode 100755 index 0000000..af25f21 --- /dev/null +++ b/audiomass-editor/src/index.html @@ -0,0 +1,72 @@ + + + + AudioMass - Audio Editor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/audiomass-editor/src/keys.js b/audiomass-editor/src/keys.js new file mode 100755 index 0000000..14649e7 --- /dev/null +++ b/audiomass-editor/src/keys.js @@ -0,0 +1,89 @@ +(function( w, d, PKAE ) { + 'use strict'; + + function KeyHandler () { + var q = this; + + q.keyMap = {}; // holds a map of all the active keys + q.callbacks = {}; // callbacks for when a key combintation becomes active + q.singleCallbacks = {}; // callbacks to the 'keypress' event - not required + + q.addCallback = function (callback_name, callback_function, keys) { + q.callbacks[ callback_name ] = { + keys : keys, + callback : callback_function + }; + }; + q.addSingleCallback = function (callback_name, callback_function, key) { + q.singleCallbacks[ callback_name ] = { + key : key, + callback : callback_function + }; + }; + q.removeCallback = function ( callback_name ) { + q.callbacks[ callback_name ] = null; + }; + + d.addEventListener ('keydown', function ( e ) { + var keyCode = e.keyCode; + + q.keyDown (keyCode, e); + }); + + q.keyDown = function (keyCode, e ) { + q.keyMap[keyCode] = 1; + + for (var key in q.callbacks) { + var group = q.callbacks[key]; + if (!group) continue; + + var l = group.keys.length; + var all_ok = true; + while (l-- > 0) { + if (!q.keyMap[group.keys[l]]) + { + all_ok = false; + break; + } + } + + all_ok && group.callback && group.callback ( keyCode, q.keyMap, e ); + } + }; + + q.keyUp = function ( keyCode ) { + q.keyMap[keyCode] = 0; + }; + + q.keyPress = function ( keyCode, e ) { + for (var key in q.singleCallbacks) { + var group = q.singleCallbacks[key]; + if (!group) continue; + + if (group.key === keyCode) + group.callback && group.callback ( e ); + } + }; + + d.addEventListener ('keyup', function ( e ) { + var keyCode = e.keyCode; + q.keyUp (keyCode); + }); + + d.addEventListener ('keypress', function ( e ) { + var keyCode = e.keyCode; + + q.keyPress (keyCode, e); + }); + + w.addEventListener ('blur', function ( e ) { + q.keyMap = {}; + }, false); + d.addEventListener ('contextmenu', function( e ) { + e.preventDefault(); + }, false); + }; + + PKAE._deps.keyhandler = KeyHandler; + +})( window, document, PKAudioEditor ); \ No newline at end of file diff --git a/audiomass-editor/src/lame.js b/audiomass-editor/src/lame.js new file mode 100755 index 0000000..32da817 --- /dev/null +++ b/audiomass-editor/src/lame.js @@ -0,0 +1,15591 @@ +function lamejs() { +function new_byte(count) { + return new Int8Array(count); +} + +function new_short(count) { + return new Int16Array(count); +} + +function new_int(count) { + return new Int32Array(count); +} + +function new_float(count) { + return new Float32Array(count); +} + +function new_double(count) { + return new Float64Array(count); +} + +function new_float_n(args) { + if (args.length == 1) { + return new_float(args[0]); + } + var sz = args[0]; + args = args.slice(1); + var A = []; + for (var i = 0; i < sz; i++) { + A.push(new_float_n(args)); + } + return A; +} +function new_int_n(args) { + if (args.length == 1) { + return new_int(args[0]); + } + var sz = args[0]; + args = args.slice(1); + var A = []; + for (var i = 0; i < sz; i++) { + A.push(new_int_n(args)); + } + return A; +} + +function new_short_n(args) { + if (args.length == 1) { + return new_short(args[0]); + } + var sz = args[0]; + args = args.slice(1); + var A = []; + for (var i = 0; i < sz; i++) { + A.push(new_short_n(args)); + } + return A; +} + +function new_array_n(args) { + if (args.length == 1) { + return new Array(args[0]); + } + var sz = args[0]; + args = args.slice(1); + var A = []; + for (var i = 0; i < sz; i++) { + A.push(new_array_n(args)); + } + return A; +} + + +var Arrays = {}; + +Arrays.fill = function (a, fromIndex, toIndex, val) { + if (arguments.length == 2) { + for (var i = 0; i < a.length; i++) { + a[i] = arguments[1]; + } + } else { + for (var i = fromIndex; i < toIndex; i++) { + a[i] = val; + } + } +}; + +var System = {}; + +System.arraycopy = function (src, srcPos, dest, destPos, length) { + var srcEnd = srcPos + length; + while (srcPos < srcEnd) + dest[destPos++] = src[srcPos++]; +}; + + +var Util = {}; +Util.SQRT2 = 1.41421356237309504880; +Util.FAST_LOG10 = function (x) { + return Math.log10(x); +}; + +Util.FAST_LOG10_X = function (x, y) { + return Math.log10(x) * y; +}; + +function ShortBlock(ordinal) { + this.ordinal = ordinal; +} +/** + * LAME may use them, even different block types for L/R. + */ +ShortBlock.short_block_allowed = new ShortBlock(0); +/** + * LAME may use them, but always same block types in L/R. + */ +ShortBlock.short_block_coupled = new ShortBlock(1); +/** + * LAME will not use short blocks, long blocks only. + */ +ShortBlock.short_block_dispensed = new ShortBlock(2); +/** + * LAME will not use long blocks, short blocks only. + */ +ShortBlock.short_block_forced = new ShortBlock(3); + +var Float = {}; +Float.MAX_VALUE = 3.4028235e+38; + +function VbrMode(ordinal) { + this.ordinal = ordinal; +} +VbrMode.vbr_off = new VbrMode(0); +VbrMode.vbr_mt = new VbrMode(1); +VbrMode.vbr_rh = new VbrMode(2); +VbrMode.vbr_abr = new VbrMode(3); +VbrMode.vbr_mtrh = new VbrMode(4); +VbrMode.vbr_default = VbrMode.vbr_mtrh; + +var assert = function (x) { + //console.assert(x); +}; + +var module_exports = { + "System": System, + "VbrMode": VbrMode, + "Float": Float, + "ShortBlock": ShortBlock, + "Util": Util, + "Arrays": Arrays, + "new_array_n": new_array_n, + "new_byte": new_byte, + "new_double": new_double, + "new_float": new_float, + "new_float_n": new_float_n, + "new_int": new_int, + "new_int_n": new_int_n, + "new_short": new_short, + "new_short_n": new_short_n, + "assert": assert +}; +//package mp3; + +/* MPEG modes */ +function MPEGMode(ordinal) { + var _ordinal = ordinal; + this.ordinal = function () { + return _ordinal; + } +} + +MPEGMode.STEREO = new MPEGMode(0); +MPEGMode.JOINT_STEREO = new MPEGMode(1); +MPEGMode.DUAL_CHANNEL = new MPEGMode(2); +MPEGMode.MONO = new MPEGMode(3); +MPEGMode.NOT_SET = new MPEGMode(4); + +function Version() { + + /** + * URL for the LAME website. + */ + var LAME_URL = "http://www.mp3dev.org/"; + + /** + * Major version number. + */ + var LAME_MAJOR_VERSION = 3; + /** + * Minor version number. + */ + var LAME_MINOR_VERSION = 98; + /** + * Patch level. + */ + var LAME_PATCH_VERSION = 4; + + /** + * Major version number. + */ + var PSY_MAJOR_VERSION = 0; + /** + * Minor version number. + */ + var PSY_MINOR_VERSION = 93; + + /** + * A string which describes the version of LAME. + * + * @return string which describes the version of LAME + */ + this.getLameVersion = function () { + // primary to write screen reports + return (LAME_MAJOR_VERSION + "." + LAME_MINOR_VERSION + "." + LAME_PATCH_VERSION); + } + + /** + * The short version of the LAME version string. + * + * @return short version of the LAME version string + */ + this.getLameShortVersion = function () { + // Adding date and time to version string makes it harder for output + // validation + return (LAME_MAJOR_VERSION + "." + LAME_MINOR_VERSION + "." + LAME_PATCH_VERSION); + } + + /** + * The shortest version of the LAME version string. + * + * @return shortest version of the LAME version string + */ + this.getLameVeryShortVersion = function () { + // Adding date and time to version string makes it harder for output + return ("LAME" + LAME_MAJOR_VERSION + "." + LAME_MINOR_VERSION + "r"); + } + + /** + * String which describes the version of GPSYCHO + * + * @return string which describes the version of GPSYCHO + */ + this.getPsyVersion = function () { + return (PSY_MAJOR_VERSION + "." + PSY_MINOR_VERSION); + } + + /** + * String which is a URL for the LAME website. + * + * @return string which is a URL for the LAME website + */ + this.getLameUrl = function () { + return LAME_URL; + } + + /** + * Quite useless for a java version, however we are compatible ;-) + * + * @return "32bits" + */ + this.getLameOsBitness = function () { + return "32bits"; + } + +} + +/* + * MP3 huffman table selecting and bit counting + * + * Copyright (c) 1999-2005 Takehiro TOMINAGA + * Copyright (c) 2002-2005 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: Takehiro.java,v 1.26 2011/05/24 20:48:06 kenchis Exp $ */ + +//package mp3; + +//import java.util.Arrays; + + + +function Takehiro() { + + var qupvt = null; + this.qupvt = null; + + this.setModules = function (_qupvt) { + this.qupvt = _qupvt; + qupvt = _qupvt; + } + + function Bits(b) { + this.bits = 0 | b; + } + + var subdv_table = [[0, 0], /* 0 bands */ + [0, 0], /* 1 bands */ + [0, 0], /* 2 bands */ + [0, 0], /* 3 bands */ + [0, 0], /* 4 bands */ + [0, 1], /* 5 bands */ + [1, 1], /* 6 bands */ + [1, 1], /* 7 bands */ + [1, 2], /* 8 bands */ + [2, 2], /* 9 bands */ + [2, 3], /* 10 bands */ + [2, 3], /* 11 bands */ + [3, 4], /* 12 bands */ + [3, 4], /* 13 bands */ + [3, 4], /* 14 bands */ + [4, 5], /* 15 bands */ + [4, 5], /* 16 bands */ + [4, 6], /* 17 bands */ + [5, 6], /* 18 bands */ + [5, 6], /* 19 bands */ + [5, 7], /* 20 bands */ + [6, 7], /* 21 bands */ + [6, 7], /* 22 bands */ + ]; + + /** + * nonlinear quantization of xr More accurate formula than the ISO formula. + * Takes into account the fact that we are quantizing xr . ix, but we want + * ix^4/3 to be as close as possible to x^4/3. (taking the nearest int would + * mean ix is as close as possible to xr, which is different.) + * + * From Segher Boessenkool 11/1999 + * + * 09/2000: ASM code removed in favor of IEEE754 hack by Takehiro Tominaga. + * If you need the ASM code, check CVS circa Aug 2000. + * + * 01/2004: Optimizations by Gabriel Bouvigne + */ + function quantize_lines_xrpow_01(l, istep, xr, xrPos, ix, ixPos) { + var compareval0 = (1.0 - 0.4054) / istep; + + l = l >> 1; + while ((l--) != 0) { + ix[ixPos++] = (compareval0 > xr[xrPos++]) ? 0 : 1; + ix[ixPos++] = (compareval0 > xr[xrPos++]) ? 0 : 1; + } + } + + /** + * XRPOW_FTOI is a macro to convert floats to ints.
+ * if XRPOW_FTOI(x) = nearest_int(x), then QUANTFAC(x)=adj43asm[x]
+ * ROUNDFAC= -0.0946
+ * + * if XRPOW_FTOI(x) = floor(x), then QUANTFAC(x)=asj43[x]
+ * ROUNDFAC=0.4054
+ * + * Note: using floor() or 0| is extremely slow. On machines where the + * TAKEHIRO_IEEE754_HACK code above does not work, it is worthwile to write + * some ASM for XRPOW_FTOI(). + */ + function quantize_lines_xrpow(l, istep, xr, xrPos, ix, ixPos) { + + l = l >> 1; + var remaining = l % 2; + l = l >> 1; + while (l-- != 0) { + var x0, x1, x2, x3; + var rx0, rx1, rx2, rx3; + + x0 = xr[xrPos++] * istep; + x1 = xr[xrPos++] * istep; + rx0 = 0 | x0; + x2 = xr[xrPos++] * istep; + rx1 = 0 | x1; + x3 = xr[xrPos++] * istep; + rx2 = 0 | x2; + x0 += qupvt.adj43[rx0]; + rx3 = 0 | x3; + x1 += qupvt.adj43[rx1]; + ix[ixPos++] = 0 | x0; + x2 += qupvt.adj43[rx2]; + ix[ixPos++] = 0 | x1; + x3 += qupvt.adj43[rx3]; + ix[ixPos++] = 0 | x2; + ix[ixPos++] = 0 | x3; + } + if (remaining != 0) { + var x0, x1; + var rx0, rx1; + + x0 = xr[xrPos++] * istep; + x1 = xr[xrPos++] * istep; + rx0 = 0 | x0; + rx1 = 0 | x1; + x0 += qupvt.adj43[rx0]; + x1 += qupvt.adj43[rx1]; + ix[ixPos++] = 0 | x0; + ix[ixPos++] = 0 | x1; + } + } + + /** + * Quantization function This function will select which lines to quantize + * and call the proper quantization function + */ + function quantize_xrpow(xp, pi, istep, codInfo, prevNoise) { + /* quantize on xr^(3/4) instead of xr */ + var sfb; + var sfbmax; + var j = 0; + var prev_data_use; + var accumulate = 0; + var accumulate01 = 0; + var xpPos = 0; + var iData = pi; + var iDataPos = 0; + var acc_iData = iData; + var acc_iDataPos = 0; + var acc_xp = xp; + var acc_xpPos = 0; + + /* + * Reusing previously computed data does not seems to work if global + * gain is changed. Finding why it behaves this way would allow to use a + * cache of previously computed values (let's 10 cached values per sfb) + * that would probably provide a noticeable speedup + */ + prev_data_use = (prevNoise != null && (codInfo.global_gain == prevNoise.global_gain)); + + if (codInfo.block_type == Encoder.SHORT_TYPE) + sfbmax = 38; + else + sfbmax = 21; + + for (sfb = 0; sfb <= sfbmax; sfb++) { + var step = -1; + + if (prev_data_use || codInfo.block_type == Encoder.NORM_TYPE) { + step = codInfo.global_gain + - ((codInfo.scalefac[sfb] + (codInfo.preflag != 0 ? qupvt.pretab[sfb] + : 0)) << (codInfo.scalefac_scale + 1)) + - codInfo.subblock_gain[codInfo.window[sfb]] * 8; + } + if (prev_data_use && (prevNoise.step[sfb] == step)) { + /* + * do not recompute this part, but compute accumulated lines + */ + if (accumulate != 0) { + quantize_lines_xrpow(accumulate, istep, acc_xp, acc_xpPos, + acc_iData, acc_iDataPos); + accumulate = 0; + } + if (accumulate01 != 0) { + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, + acc_xpPos, acc_iData, acc_iDataPos); + accumulate01 = 0; + } + } else { /* should compute this part */ + var l = codInfo.width[sfb]; + + if ((j + codInfo.width[sfb]) > codInfo.max_nonzero_coeff) { + /* do not compute upper zero part */ + var usefullsize; + usefullsize = codInfo.max_nonzero_coeff - j + 1; + Arrays.fill(pi, codInfo.max_nonzero_coeff, 576, 0); + l = usefullsize; + + if (l < 0) { + l = 0; + } + + /* no need to compute higher sfb values */ + sfb = sfbmax + 1; + } + + /* accumulate lines to quantize */ + if (0 == accumulate && 0 == accumulate01) { + acc_iData = iData; + acc_iDataPos = iDataPos; + acc_xp = xp; + acc_xpPos = xpPos; + } + if (prevNoise != null && prevNoise.sfb_count1 > 0 + && sfb >= prevNoise.sfb_count1 + && prevNoise.step[sfb] > 0 + && step >= prevNoise.step[sfb]) { + + if (accumulate != 0) { + quantize_lines_xrpow(accumulate, istep, acc_xp, + acc_xpPos, acc_iData, acc_iDataPos); + accumulate = 0; + acc_iData = iData; + acc_iDataPos = iDataPos; + acc_xp = xp; + acc_xpPos = xpPos; + } + accumulate01 += l; + } else { + if (accumulate01 != 0) { + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, + acc_xpPos, acc_iData, acc_iDataPos); + accumulate01 = 0; + acc_iData = iData; + acc_iDataPos = iDataPos; + acc_xp = xp; + acc_xpPos = xpPos; + } + accumulate += l; + } + + if (l <= 0) { + /* + * rh: 20040215 may happen due to "prev_data_use" + * optimization + */ + if (accumulate01 != 0) { + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, + acc_xpPos, acc_iData, acc_iDataPos); + accumulate01 = 0; + } + if (accumulate != 0) { + quantize_lines_xrpow(accumulate, istep, acc_xp, + acc_xpPos, acc_iData, acc_iDataPos); + accumulate = 0; + } + + break; + /* ends for-loop */ + } + } + if (sfb <= sfbmax) { + iDataPos += codInfo.width[sfb]; + xpPos += codInfo.width[sfb]; + j += codInfo.width[sfb]; + } + } + if (accumulate != 0) { /* last data part */ + quantize_lines_xrpow(accumulate, istep, acc_xp, acc_xpPos, + acc_iData, acc_iDataPos); + accumulate = 0; + } + if (accumulate01 != 0) { /* last data part */ + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, acc_xpPos, + acc_iData, acc_iDataPos); + accumulate01 = 0; + } + + } + + /** + * ix_max + */ + function ix_max(ix, ixPos, endPos) { + var max1 = 0, max2 = 0; + + do { + var x1 = ix[ixPos++]; + var x2 = ix[ixPos++]; + if (max1 < x1) + max1 = x1; + + if (max2 < x2) + max2 = x2; + } while (ixPos < endPos); + if (max1 < max2) + max1 = max2; + return max1; + } + + function count_bit_ESC(ix, ixPos, end, t1, t2, s) { + /* ESC-table is used */ + var linbits = Tables.ht[t1].xlen * 65536 + Tables.ht[t2].xlen; + var sum = 0, sum2; + + do { + var x = ix[ixPos++]; + var y = ix[ixPos++]; + + if (x != 0) { + if (x > 14) { + x = 15; + sum += linbits; + } + x *= 16; + } + + if (y != 0) { + if (y > 14) { + y = 15; + sum += linbits; + } + x += y; + } + + sum += Tables.largetbl[x]; + } while (ixPos < end); + + sum2 = sum & 0xffff; + sum >>= 16; + + if (sum > sum2) { + sum = sum2; + t1 = t2; + } + + s.bits += sum; + return t1; + } + + function count_bit_noESC(ix, ixPos, end, s) { + /* No ESC-words */ + var sum1 = 0; + var hlen1 = Tables.ht[1].hlen; + + do { + var x = ix[ixPos + 0] * 2 + ix[ixPos + 1]; + ixPos += 2; + sum1 += hlen1[x]; + } while (ixPos < end); + + s.bits += sum1; + return 1; + } + + function count_bit_noESC_from2(ix, ixPos, end, t1, s) { + /* No ESC-words */ + var sum = 0, sum2; + var xlen = Tables.ht[t1].xlen; + var hlen; + if (t1 == 2) + hlen = Tables.table23; + else + hlen = Tables.table56; + + do { + var x = ix[ixPos + 0] * xlen + ix[ixPos + 1]; + ixPos += 2; + sum += hlen[x]; + } while (ixPos < end); + + sum2 = sum & 0xffff; + sum >>= 16; + + if (sum > sum2) { + sum = sum2; + t1++; + } + + s.bits += sum; + return t1; + } + + function count_bit_noESC_from3(ix, ixPos, end, t1, s) { + /* No ESC-words */ + var sum1 = 0; + var sum2 = 0; + var sum3 = 0; + var xlen = Tables.ht[t1].xlen; + var hlen1 = Tables.ht[t1].hlen; + var hlen2 = Tables.ht[t1 + 1].hlen; + var hlen3 = Tables.ht[t1 + 2].hlen; + + do { + var x = ix[ixPos + 0] * xlen + ix[ixPos + 1]; + ixPos += 2; + sum1 += hlen1[x]; + sum2 += hlen2[x]; + sum3 += hlen3[x]; + } while (ixPos < end); + var t = t1; + if (sum1 > sum2) { + sum1 = sum2; + t++; + } + if (sum1 > sum3) { + sum1 = sum3; + t = t1 + 2; + } + s.bits += sum1; + + return t; + } + + /*************************************************************************/ + /* choose table */ + /*************************************************************************/ + + var huf_tbl_noESC = [1, 2, 5, 7, 7, 10, 10, 13, 13, + 13, 13, 13, 13, 13, 13]; + + /** + * Choose the Huffman table that will encode ix[begin..end] with the fewest + * bits. + * + * Note: This code contains knowledge about the sizes and characteristics of + * the Huffman tables as defined in the IS (Table B.7), and will not work + * with any arbitrary tables. + */ + function choose_table(ix, ixPos, endPos, s) { + var max = ix_max(ix, ixPos, endPos); + + switch (max) { + case 0: + return max; + + case 1: + return count_bit_noESC(ix, ixPos, endPos, s); + + case 2: + case 3: + return count_bit_noESC_from2(ix, ixPos, endPos, + huf_tbl_noESC[max - 1], s); + + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + return count_bit_noESC_from3(ix, ixPos, endPos, + huf_tbl_noESC[max - 1], s); + + default: + /* try tables with linbits */ + if (max > QuantizePVT.IXMAX_VAL) { + s.bits = QuantizePVT.LARGE_BITS; + return -1; + } + max -= 15; + var choice2; + for (choice2 = 24; choice2 < 32; choice2++) { + if (Tables.ht[choice2].linmax >= max) { + break; + } + } + var choice; + for (choice = choice2 - 8; choice < 24; choice++) { + if (Tables.ht[choice].linmax >= max) { + break; + } + } + return count_bit_ESC(ix, ixPos, endPos, choice, choice2, s); + } + } + + /** + * count_bit + */ + this.noquant_count_bits = function (gfc, gi, prev_noise) { + var ix = gi.l3_enc; + var i = Math.min(576, ((gi.max_nonzero_coeff + 2) >> 1) << 1); + + if (prev_noise != null) + prev_noise.sfb_count1 = 0; + + /* Determine count1 region */ + for (; i > 1; i -= 2) + if ((ix[i - 1] | ix[i - 2]) != 0) + break; + gi.count1 = i; + + /* Determines the number of bits to encode the quadruples. */ + var a1 = 0; + var a2 = 0; + for (; i > 3; i -= 4) { + var p; + /* hack to check if all values <= 1 */ + //throw "TODO: HACK if ((((long) ix[i - 1] | (long) ix[i - 2] | (long) ix[i - 3] | (long) ix[i - 4]) & 0xffffffffL) > 1L " + //if (true) { + if (((ix[i - 1] | ix[i - 2] | ix[i - 3] | ix[i - 4]) & 0x7fffffff) > 1) { + break; + } + p = ((ix[i - 4] * 2 + ix[i - 3]) * 2 + ix[i - 2]) * 2 + ix[i - 1]; + a1 += Tables.t32l[p]; + a2 += Tables.t33l[p]; + } + var bits = a1; + gi.count1table_select = 0; + if (a1 > a2) { + bits = a2; + gi.count1table_select = 1; + } + + gi.count1bits = bits; + gi.big_values = i; + if (i == 0) + return bits; + + if (gi.block_type == Encoder.SHORT_TYPE) { + a1 = 3 * gfc.scalefac_band.s[3]; + if (a1 > gi.big_values) + a1 = gi.big_values; + a2 = gi.big_values; + + } else if (gi.block_type == Encoder.NORM_TYPE) { + /* bv_scf has 576 entries (0..575) */ + a1 = gi.region0_count = gfc.bv_scf[i - 2]; + a2 = gi.region1_count = gfc.bv_scf[i - 1]; + + a2 = gfc.scalefac_band.l[a1 + a2 + 2]; + a1 = gfc.scalefac_band.l[a1 + 1]; + if (a2 < i) { + var bi = new Bits(bits); + gi.table_select[2] = choose_table(ix, a2, i, bi); + bits = bi.bits; + } + } else { + gi.region0_count = 7; + /* gi.region1_count = SBPSY_l - 7 - 1; */ + gi.region1_count = Encoder.SBMAX_l - 1 - 7 - 1; + a1 = gfc.scalefac_band.l[7 + 1]; + a2 = i; + if (a1 > a2) { + a1 = a2; + } + } + + /* have to allow for the case when bigvalues < region0 < region1 */ + /* (and region0, region1 are ignored) */ + a1 = Math.min(a1, i); + a2 = Math.min(a2, i); + + + /* Count the number of bits necessary to code the bigvalues region. */ + if (0 < a1) { + var bi = new Bits(bits); + gi.table_select[0] = choose_table(ix, 0, a1, bi); + bits = bi.bits; + } + if (a1 < a2) { + var bi = new Bits(bits); + gi.table_select[1] = choose_table(ix, a1, a2, bi); + bits = bi.bits; + } + if (gfc.use_best_huffman == 2) { + gi.part2_3_length = bits; + best_huffman_divide(gfc, gi); + bits = gi.part2_3_length; + } + + if (prev_noise != null) { + if (gi.block_type == Encoder.NORM_TYPE) { + var sfb = 0; + while (gfc.scalefac_band.l[sfb] < gi.big_values) { + sfb++; + } + prev_noise.sfb_count1 = sfb; + } + } + + return bits; + } + + this.count_bits = function (gfc, xr, gi, prev_noise) { + var ix = gi.l3_enc; + + /* since quantize_xrpow uses table lookup, we need to check this first: */ + var w = (QuantizePVT.IXMAX_VAL) / qupvt.IPOW20(gi.global_gain); + + if (gi.xrpow_max > w) + return QuantizePVT.LARGE_BITS; + + quantize_xrpow(xr, ix, qupvt.IPOW20(gi.global_gain), gi, prev_noise); + + if ((gfc.substep_shaping & 2) != 0) { + var j = 0; + /* 0.634521682242439 = 0.5946*2**(.5*0.1875) */ + var gain = gi.global_gain + gi.scalefac_scale; + var roundfac = 0.634521682242439 / qupvt.IPOW20(gain); + for (var sfb = 0; sfb < gi.sfbmax; sfb++) { + var width = gi.width[sfb]; + if (0 == gfc.pseudohalf[sfb]) { + j += width; + } else { + var k; + for (k = j, j += width; k < j; ++k) { + ix[k] = (xr[k] >= roundfac) ? ix[k] : 0; + } + } + } + } + return this.noquant_count_bits(gfc, gi, prev_noise); + } + + /** + * re-calculate the best scalefac_compress using scfsi the saved bits are + * kept in the bit reservoir. + */ + function recalc_divide_init(gfc, cod_info, ix, r01_bits, r01_div, r0_tbl, r1_tbl) { + var bigv = cod_info.big_values; + + for (var r0 = 0; r0 <= 7 + 15; r0++) { + r01_bits[r0] = QuantizePVT.LARGE_BITS; + } + + for (var r0 = 0; r0 < 16; r0++) { + var a1 = gfc.scalefac_band.l[r0 + 1]; + if (a1 >= bigv) + break; + var r0bits = 0; + var bi = new Bits(r0bits); + var r0t = choose_table(ix, 0, a1, bi); + r0bits = bi.bits; + + for (var r1 = 0; r1 < 8; r1++) { + var a2 = gfc.scalefac_band.l[r0 + r1 + 2]; + if (a2 >= bigv) + break; + var bits = r0bits; + bi = new Bits(bits); + var r1t = choose_table(ix, a1, a2, bi); + bits = bi.bits; + if (r01_bits[r0 + r1] > bits) { + r01_bits[r0 + r1] = bits; + r01_div[r0 + r1] = r0; + r0_tbl[r0 + r1] = r0t; + r1_tbl[r0 + r1] = r1t; + } + } + } + } + + function recalc_divide_sub(gfc, cod_info2, gi, ix, r01_bits, r01_div, r0_tbl, r1_tbl) { + var bigv = cod_info2.big_values; + + for (var r2 = 2; r2 < Encoder.SBMAX_l + 1; r2++) { + var a2 = gfc.scalefac_band.l[r2]; + if (a2 >= bigv) + break; + var bits = r01_bits[r2 - 2] + cod_info2.count1bits; + if (gi.part2_3_length <= bits) + break; + + var bi = new Bits(bits); + var r2t = choose_table(ix, a2, bigv, bi); + bits = bi.bits; + if (gi.part2_3_length <= bits) + continue; + + gi.assign(cod_info2); + gi.part2_3_length = bits; + gi.region0_count = r01_div[r2 - 2]; + gi.region1_count = r2 - 2 - r01_div[r2 - 2]; + gi.table_select[0] = r0_tbl[r2 - 2]; + gi.table_select[1] = r1_tbl[r2 - 2]; + gi.table_select[2] = r2t; + } + } + + this.best_huffman_divide = function (gfc, gi) { + var cod_info2 = new GrInfo(); + var ix = gi.l3_enc; + var r01_bits = new_int(7 + 15 + 1); + var r01_div = new_int(7 + 15 + 1); + var r0_tbl = new_int(7 + 15 + 1); + var r1_tbl = new_int(7 + 15 + 1); + + /* SHORT BLOCK stuff fails for MPEG2 */ + if (gi.block_type == Encoder.SHORT_TYPE && gfc.mode_gr == 1) + return; + + cod_info2.assign(gi); + if (gi.block_type == Encoder.NORM_TYPE) { + recalc_divide_init(gfc, gi, ix, r01_bits, r01_div, r0_tbl, r1_tbl); + recalc_divide_sub(gfc, cod_info2, gi, ix, r01_bits, r01_div, + r0_tbl, r1_tbl); + } + var i = cod_info2.big_values; + if (i == 0 || (ix[i - 2] | ix[i - 1]) > 1) + return; + + i = gi.count1 + 2; + if (i > 576) + return; + + /* Determines the number of bits to encode the quadruples. */ + cod_info2.assign(gi); + cod_info2.count1 = i; + var a1 = 0; + var a2 = 0; + + + for (; i > cod_info2.big_values; i -= 4) { + var p = ((ix[i - 4] * 2 + ix[i - 3]) * 2 + ix[i - 2]) * 2 + + ix[i - 1]; + a1 += Tables.t32l[p]; + a2 += Tables.t33l[p]; + } + cod_info2.big_values = i; + + cod_info2.count1table_select = 0; + if (a1 > a2) { + a1 = a2; + cod_info2.count1table_select = 1; + } + + cod_info2.count1bits = a1; + + if (cod_info2.block_type == Encoder.NORM_TYPE) + recalc_divide_sub(gfc, cod_info2, gi, ix, r01_bits, r01_div, + r0_tbl, r1_tbl); + else { + /* Count the number of bits necessary to code the bigvalues region. */ + cod_info2.part2_3_length = a1; + a1 = gfc.scalefac_band.l[7 + 1]; + if (a1 > i) { + a1 = i; + } + if (a1 > 0) { + var bi = new Bits(cod_info2.part2_3_length); + cod_info2.table_select[0] = choose_table(ix, 0, a1, bi); + cod_info2.part2_3_length = bi.bits; + } + if (i > a1) { + var bi = new Bits(cod_info2.part2_3_length); + cod_info2.table_select[1] = choose_table(ix, a1, i, bi); + cod_info2.part2_3_length = bi.bits; + } + if (gi.part2_3_length > cod_info2.part2_3_length) + gi.assign(cod_info2); + } + } + + var slen1_n = [1, 1, 1, 1, 8, 2, 2, 2, 4, 4, 4, 8, 8, 8, 16, 16]; + var slen2_n = [1, 2, 4, 8, 1, 2, 4, 8, 2, 4, 8, 2, 4, 8, 4, 8]; + var slen1_tab = [0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4]; + var slen2_tab = [0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3]; + Takehiro.slen1_tab = slen1_tab; + Takehiro.slen2_tab = slen2_tab; + + function scfsi_calc(ch, l3_side) { + var sfb; + var gi = l3_side.tt[1][ch]; + var g0 = l3_side.tt[0][ch]; + + for (var i = 0; i < Tables.scfsi_band.length - 1; i++) { + for (sfb = Tables.scfsi_band[i]; sfb < Tables.scfsi_band[i + 1]; sfb++) { + if (g0.scalefac[sfb] != gi.scalefac[sfb] + && gi.scalefac[sfb] >= 0) + break; + } + if (sfb == Tables.scfsi_band[i + 1]) { + for (sfb = Tables.scfsi_band[i]; sfb < Tables.scfsi_band[i + 1]; sfb++) { + gi.scalefac[sfb] = -1; + } + l3_side.scfsi[ch][i] = 1; + } + } + var s1 = 0; + var c1 = 0; + for (sfb = 0; sfb < 11; sfb++) { + if (gi.scalefac[sfb] == -1) + continue; + c1++; + if (s1 < gi.scalefac[sfb]) + s1 = gi.scalefac[sfb]; + } + var s2 = 0; + var c2 = 0; + for (; sfb < Encoder.SBPSY_l; sfb++) { + if (gi.scalefac[sfb] == -1) + continue; + c2++; + if (s2 < gi.scalefac[sfb]) + s2 = gi.scalefac[sfb]; + } + + for (var i = 0; i < 16; i++) { + if (s1 < slen1_n[i] && s2 < slen2_n[i]) { + var c = slen1_tab[i] * c1 + slen2_tab[i] * c2; + if (gi.part2_length > c) { + gi.part2_length = c; + gi.scalefac_compress = i; + } + } + } + } + + /** + * Find the optimal way to store the scalefactors. Only call this routine + * after final scalefactors have been chosen and the channel/granule will + * not be re-encoded. + */ + this.best_scalefac_store = function (gfc, gr, ch, l3_side) { + /* use scalefac_scale if we can */ + var gi = l3_side.tt[gr][ch]; + var sfb, i, j, l; + var recalc = 0; + + /* + * remove scalefacs from bands with ix=0. This idea comes from the AAC + * ISO docs. added mt 3/00 + */ + /* check if l3_enc=0 */ + j = 0; + for (sfb = 0; sfb < gi.sfbmax; sfb++) { + var width = gi.width[sfb]; + j += width; + for (l = -width; l < 0; l++) { + if (gi.l3_enc[l + j] != 0) + break; + } + if (l == 0) + gi.scalefac[sfb] = recalc = -2; + /* anything goes. */ + /* + * only best_scalefac_store and calc_scfsi know--and only they + * should know--about the magic number -2. + */ + } + + if (0 == gi.scalefac_scale && 0 == gi.preflag) { + var s = 0; + for (sfb = 0; sfb < gi.sfbmax; sfb++) + if (gi.scalefac[sfb] > 0) + s |= gi.scalefac[sfb]; + + if (0 == (s & 1) && s != 0) { + for (sfb = 0; sfb < gi.sfbmax; sfb++) + if (gi.scalefac[sfb] > 0) + gi.scalefac[sfb] >>= 1; + + gi.scalefac_scale = recalc = 1; + } + } + + if (0 == gi.preflag && gi.block_type != Encoder.SHORT_TYPE + && gfc.mode_gr == 2) { + for (sfb = 11; sfb < Encoder.SBPSY_l; sfb++) + if (gi.scalefac[sfb] < qupvt.pretab[sfb] + && gi.scalefac[sfb] != -2) + break; + if (sfb == Encoder.SBPSY_l) { + for (sfb = 11; sfb < Encoder.SBPSY_l; sfb++) + if (gi.scalefac[sfb] > 0) + gi.scalefac[sfb] -= qupvt.pretab[sfb]; + + gi.preflag = recalc = 1; + } + } + + for (i = 0; i < 4; i++) + l3_side.scfsi[ch][i] = 0; + + if (gfc.mode_gr == 2 && gr == 1 + && l3_side.tt[0][ch].block_type != Encoder.SHORT_TYPE + && l3_side.tt[1][ch].block_type != Encoder.SHORT_TYPE) { + scfsi_calc(ch, l3_side); + recalc = 0; + } + for (sfb = 0; sfb < gi.sfbmax; sfb++) { + if (gi.scalefac[sfb] == -2) { + gi.scalefac[sfb] = 0; + /* if anything goes, then 0 is a good choice */ + } + } + if (recalc != 0) { + if (gfc.mode_gr == 2) { + this.scale_bitcount(gi); + } else { + this.scale_bitcount_lsf(gfc, gi); + } + } + } + + function all_scalefactors_not_negative(scalefac, n) { + for (var i = 0; i < n; ++i) { + if (scalefac[i] < 0) + return false; + } + return true; + } + + /** + * number of bits used to encode scalefacs. + * + * 18*slen1_tab[i] + 18*slen2_tab[i] + */ + var scale_short = [0, 18, 36, 54, 54, 36, 54, 72, + 54, 72, 90, 72, 90, 108, 108, 126]; + + /** + * number of bits used to encode scalefacs. + * + * 17*slen1_tab[i] + 18*slen2_tab[i] + */ + var scale_mixed = [0, 18, 36, 54, 51, 35, 53, 71, + 52, 70, 88, 69, 87, 105, 104, 122]; + + /** + * number of bits used to encode scalefacs. + * + * 11*slen1_tab[i] + 10*slen2_tab[i] + */ + var scale_long = [0, 10, 20, 30, 33, 21, 31, 41, 32, 42, + 52, 43, 53, 63, 64, 74]; + + /** + * Also calculates the number of bits necessary to code the scalefactors. + */ + this.scale_bitcount = function (cod_info) { + var k, sfb, max_slen1 = 0, max_slen2 = 0; + + /* maximum values */ + var tab; + var scalefac = cod_info.scalefac; + + + if (cod_info.block_type == Encoder.SHORT_TYPE) { + tab = scale_short; + if (cod_info.mixed_block_flag != 0) + tab = scale_mixed; + } else { /* block_type == 1,2,or 3 */ + tab = scale_long; + if (0 == cod_info.preflag) { + for (sfb = 11; sfb < Encoder.SBPSY_l; sfb++) + if (scalefac[sfb] < qupvt.pretab[sfb]) + break; + + if (sfb == Encoder.SBPSY_l) { + cod_info.preflag = 1; + for (sfb = 11; sfb < Encoder.SBPSY_l; sfb++) + scalefac[sfb] -= qupvt.pretab[sfb]; + } + } + } + + for (sfb = 0; sfb < cod_info.sfbdivide; sfb++) + if (max_slen1 < scalefac[sfb]) + max_slen1 = scalefac[sfb]; + + for (; sfb < cod_info.sfbmax; sfb++) + if (max_slen2 < scalefac[sfb]) + max_slen2 = scalefac[sfb]; + + /* + * from Takehiro TOMINAGA 10/99 loop over *all* + * posible values of scalefac_compress to find the one which uses the + * smallest number of bits. ISO would stop at first valid index + */ + cod_info.part2_length = QuantizePVT.LARGE_BITS; + for (k = 0; k < 16; k++) { + if (max_slen1 < slen1_n[k] && max_slen2 < slen2_n[k] + && cod_info.part2_length > tab[k]) { + cod_info.part2_length = tab[k]; + cod_info.scalefac_compress = k; + } + } + return cod_info.part2_length == QuantizePVT.LARGE_BITS; + } + + /** + * table of largest scalefactor values for MPEG2 + */ + var max_range_sfac_tab = [[15, 15, 7, 7], + [15, 15, 7, 0], [7, 3, 0, 0], [15, 31, 31, 0], + [7, 7, 7, 0], [3, 3, 0, 0]]; + + /** + * Also counts the number of bits to encode the scalefacs but for MPEG 2 + * Lower sampling frequencies (24, 22.05 and 16 kHz.) + * + * This is reverse-engineered from section 2.4.3.2 of the MPEG2 IS, + * "Audio Decoding Layer III" + */ + this.scale_bitcount_lsf = function (gfc, cod_info) { + var table_number, row_in_table, partition, nr_sfb, window; + var over; + var i, sfb; + var max_sfac = new_int(4); +//var partition_table; + var scalefac = cod_info.scalefac; + + /* + * Set partition table. Note that should try to use table one, but do + * not yet... + */ + if (cod_info.preflag != 0) + table_number = 2; + else + table_number = 0; + + for (i = 0; i < 4; i++) + max_sfac[i] = 0; + + if (cod_info.block_type == Encoder.SHORT_TYPE) { + row_in_table = 1; + var partition_table = qupvt.nr_of_sfb_block[table_number][row_in_table]; + for (sfb = 0, partition = 0; partition < 4; partition++) { + nr_sfb = partition_table[partition] / 3; + for (i = 0; i < nr_sfb; i++, sfb++) + for (window = 0; window < 3; window++) + if (scalefac[sfb * 3 + window] > max_sfac[partition]) + max_sfac[partition] = scalefac[sfb * 3 + window]; + } + } else { + row_in_table = 0; + var partition_table = qupvt.nr_of_sfb_block[table_number][row_in_table]; + for (sfb = 0, partition = 0; partition < 4; partition++) { + nr_sfb = partition_table[partition]; + for (i = 0; i < nr_sfb; i++, sfb++) + if (scalefac[sfb] > max_sfac[partition]) + max_sfac[partition] = scalefac[sfb]; + } + } + + for (over = false, partition = 0; partition < 4; partition++) { + if (max_sfac[partition] > max_range_sfac_tab[table_number][partition]) + over = true; + } + if (!over) { + var slen1, slen2, slen3, slen4; + + cod_info.sfb_partition_table = qupvt.nr_of_sfb_block[table_number][row_in_table]; + for (partition = 0; partition < 4; partition++) + cod_info.slen[partition] = log2tab[max_sfac[partition]]; + + /* set scalefac_compress */ + slen1 = cod_info.slen[0]; + slen2 = cod_info.slen[1]; + slen3 = cod_info.slen[2]; + slen4 = cod_info.slen[3]; + + switch (table_number) { + case 0: + cod_info.scalefac_compress = (((slen1 * 5) + slen2) << 4) + + (slen3 << 2) + slen4; + break; + + case 1: + cod_info.scalefac_compress = 400 + (((slen1 * 5) + slen2) << 2) + + slen3; + break; + + case 2: + cod_info.scalefac_compress = 500 + (slen1 * 3) + slen2; + break; + + default: + System.err.printf("intensity stereo not implemented yet\n"); + break; + } + } + if (!over) { + cod_info.part2_length = 0; + for (partition = 0; partition < 4; partition++) + cod_info.part2_length += cod_info.slen[partition] + * cod_info.sfb_partition_table[partition]; + } + return over; + } + + /* + * Since no bands have been over-amplified, we can set scalefac_compress and + * slen[] for the formatter + */ + var log2tab = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, + 4, 4, 4, 4]; + + this.huffman_init = function (gfc) { + for (var i = 2; i <= 576; i += 2) { + var scfb_anz = 0, bv_index; + while (gfc.scalefac_band.l[++scfb_anz] < i) + ; + + bv_index = subdv_table[scfb_anz][0]; // .region0_count + while (gfc.scalefac_band.l[bv_index + 1] > i) + bv_index--; + + if (bv_index < 0) { + /* + * this is an indication that everything is going to be encoded + * as region0: bigvalues < region0 < region1 so lets set + * region0, region1 to some value larger than bigvalues + */ + bv_index = subdv_table[scfb_anz][0]; // .region0_count + } + + gfc.bv_scf[i - 2] = bv_index; + + bv_index = subdv_table[scfb_anz][1]; // .region1_count + while (gfc.scalefac_band.l[bv_index + gfc.bv_scf[i - 2] + 2] > i) + bv_index--; + + if (bv_index < 0) { + bv_index = subdv_table[scfb_anz][1]; // .region1_count + } + + gfc.bv_scf[i - 1] = bv_index; + } + } +} + +/* + * ReplayGainAnalysis - analyzes input samples and give the recommended dB change + * Copyright (C) 2001 David Robinson and Glen Sawyer + * Improvements and optimizations added by Frank Klemm, and by Marcel Muller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * concept and filter values by David Robinson (David@Robinson.org) + * -- blame him if you think the idea is flawed + * original coding by Glen Sawyer (mp3gain@hotmail.com) + * -- blame him if you think this runs too slowly, or the coding is otherwise flawed + * + * lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ ) + * -- credit him for all the _good_ programming ;) + * + * + * For an explanation of the concepts and the basic algorithms involved, go to: + * http://www.replaygain.org/ + */ + +/* + * Here's the deal. Call + * + * InitGainAnalysis ( long samplefreq ); + * + * to initialize everything. Call + * + * AnalyzeSamples ( var Float_t* left_samples, + * var Float_t* right_samples, + * size_t num_samples, + * int num_channels ); + * + * as many times as you want, with as many or as few samples as you want. + * If mono, pass the sample buffer in through left_samples, leave + * right_samples NULL, and make sure num_channels = 1. + * + * GetTitleGain() + * + * will return the recommended dB level change for all samples analyzed + * SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis(). + * + * GetAlbumGain() + * + * will return the recommended dB level change for all samples analyzed + * since InitGainAnalysis() was called and finalized with GetTitleGain(). + * + * Pseudo-code to process an album: + * + * Float_t l_samples [4096]; + * Float_t r_samples [4096]; + * size_t num_samples; + * unsigned int num_songs; + * unsigned int i; + * + * InitGainAnalysis ( 44100 ); + * for ( i = 1; i <= num_songs; i++ ) { + * while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 ) + * AnalyzeSamples ( left_samples, right_samples, num_samples, 2 ); + * fprintf ("Recommended dB change for song %2d: %+6.2 dB\n", i, GetTitleGain() ); + * } + * fprintf ("Recommended dB change for whole album: %+6.2 dB\n", GetAlbumGain() ); + */ + +/* + * So here's the main source of potential code confusion: + * + * The filters applied to the incoming samples are IIR filters, + * meaning they rely on up to number of previous samples + * AND up to number of previous filtered samples. + * + * I set up the AnalyzeSamples routine to minimize memory usage and interface + * complexity. The speed isn't compromised too much (I don't think), but the + * internal complexity is higher than it should be for such a relatively + * simple routine. + * + * Optimization/clarity suggestions are welcome. + */ + +/** + * Table entries per dB + */ +GainAnalysis.STEPS_per_dB = 100.; +/** + * Table entries for 0...MAX_dB (normal max. values are 70...80 dB) + */ +GainAnalysis.MAX_dB = 120.; +GainAnalysis.GAIN_NOT_ENOUGH_SAMPLES = -24601; +GainAnalysis.GAIN_ANALYSIS_ERROR = 0; +GainAnalysis.GAIN_ANALYSIS_OK = 1; +GainAnalysis.INIT_GAIN_ANALYSIS_ERROR = 0; +GainAnalysis.INIT_GAIN_ANALYSIS_OK = 1; + +GainAnalysis.YULE_ORDER = 10; +GainAnalysis.MAX_ORDER = GainAnalysis.YULE_ORDER; + +GainAnalysis.MAX_SAMP_FREQ = 48000; +GainAnalysis.RMS_WINDOW_TIME_NUMERATOR = 1; +GainAnalysis.RMS_WINDOW_TIME_DENOMINATOR = 20; +GainAnalysis.MAX_SAMPLES_PER_WINDOW = ((GainAnalysis.MAX_SAMP_FREQ * GainAnalysis.RMS_WINDOW_TIME_NUMERATOR) / GainAnalysis.RMS_WINDOW_TIME_DENOMINATOR + 1); + +function GainAnalysis() { + /** + * calibration value for 89dB + */ + var PINK_REF = 64.82; + + var YULE_ORDER = GainAnalysis.YULE_ORDER; + /** + * percentile which is louder than the proposed level + */ + var RMS_PERCENTILE = 0.95; + /** + * maximum allowed sample frequency [Hz] + */ + var MAX_SAMP_FREQ = GainAnalysis.MAX_SAMP_FREQ; + var RMS_WINDOW_TIME_NUMERATOR = GainAnalysis.RMS_WINDOW_TIME_NUMERATOR; + /** + * numerator / denominator = time slice size [s] + */ + var RMS_WINDOW_TIME_DENOMINATOR = GainAnalysis.RMS_WINDOW_TIME_DENOMINATOR; + /** + * max. Samples per Time slice + */ + var MAX_SAMPLES_PER_WINDOW = GainAnalysis.MAX_SAMPLES_PER_WINDOW; + + + var ABYule = [ + [0.03857599435200, -3.84664617118067, -0.02160367184185, + 7.81501653005538, -0.00123395316851, -11.34170355132042, + -0.00009291677959, 13.05504219327545, -0.01655260341619, + -12.28759895145294, 0.02161526843274, 9.48293806319790, + -0.02074045215285, -5.87257861775999, 0.00594298065125, + 2.75465861874613, 0.00306428023191, -0.86984376593551, + 0.00012025322027, 0.13919314567432, 0.00288463683916], + [0.05418656406430, -3.47845948550071, -0.02911007808948, + 6.36317777566148, -0.00848709379851, -8.54751527471874, + -0.00851165645469, 9.47693607801280, -0.00834990904936, + -8.81498681370155, 0.02245293253339, 6.85401540936998, + -0.02596338512915, -4.39470996079559, 0.01624864962975, + 2.19611684890774, -0.00240879051584, -0.75104302451432, + 0.00674613682247, 0.13149317958808, -0.00187763777362], + [0.15457299681924, -2.37898834973084, -0.09331049056315, + 2.84868151156327, -0.06247880153653, -2.64577170229825, + 0.02163541888798, 2.23697657451713, -0.05588393329856, + -1.67148153367602, 0.04781476674921, 1.00595954808547, + 0.00222312597743, -0.45953458054983, 0.03174092540049, + 0.16378164858596, -0.01390589421898, -0.05032077717131, + 0.00651420667831, 0.02347897407020, -0.00881362733839], + [0.30296907319327, -1.61273165137247, -0.22613988682123, + 1.07977492259970, -0.08587323730772, -0.25656257754070, + 0.03282930172664, -0.16276719120440, -0.00915702933434, + -0.22638893773906, -0.02364141202522, 0.39120800788284, + -0.00584456039913, -0.22138138954925, 0.06276101321749, + 0.04500235387352, -0.00000828086748, 0.02005851806501, + 0.00205861885564, 0.00302439095741, -0.02950134983287], + [0.33642304856132, -1.49858979367799, -0.25572241425570, + 0.87350271418188, -0.11828570177555, 0.12205022308084, + 0.11921148675203, -0.80774944671438, -0.07834489609479, + 0.47854794562326, -0.00469977914380, -0.12453458140019, + -0.00589500224440, -0.04067510197014, 0.05724228140351, + 0.08333755284107, 0.00832043980773, -0.04237348025746, + -0.01635381384540, 0.02977207319925, -0.01760176568150], + [0.44915256608450, -0.62820619233671, -0.14351757464547, + 0.29661783706366, -0.22784394429749, -0.37256372942400, + -0.01419140100551, 0.00213767857124, 0.04078262797139, + -0.42029820170918, -0.12398163381748, 0.22199650564824, + 0.04097565135648, 0.00613424350682, 0.10478503600251, + 0.06747620744683, -0.01863887810927, 0.05784820375801, + -0.03193428438915, 0.03222754072173, 0.00541907748707], + [0.56619470757641, -1.04800335126349, -0.75464456939302, + 0.29156311971249, 0.16242137742230, -0.26806001042947, + 0.16744243493672, 0.00819999645858, -0.18901604199609, + 0.45054734505008, 0.30931782841830, -0.33032403314006, + -0.27562961986224, 0.06739368333110, 0.00647310677246, + -0.04784254229033, 0.08647503780351, 0.01639907836189, + -0.03788984554840, 0.01807364323573, -0.00588215443421], + [0.58100494960553, -0.51035327095184, -0.53174909058578, + -0.31863563325245, -0.14289799034253, -0.20256413484477, + 0.17520704835522, 0.14728154134330, 0.02377945217615, + 0.38952639978999, 0.15558449135573, -0.23313271880868, + -0.25344790059353, -0.05246019024463, 0.01628462406333, + -0.02505961724053, 0.06920467763959, 0.02442357316099, + -0.03721611395801, 0.01818801111503, -0.00749618797172], + [0.53648789255105, -0.25049871956020, -0.42163034350696, + -0.43193942311114, -0.00275953611929, -0.03424681017675, + 0.04267842219415, -0.04678328784242, -0.10214864179676, + 0.26408300200955, 0.14590772289388, 0.15113130533216, + -0.02459864859345, -0.17556493366449, -0.11202315195388, + -0.18823009262115, -0.04060034127000, 0.05477720428674, + 0.04788665548180, 0.04704409688120, -0.02217936801134]]; + + var ABButter = [ + [0.98621192462708, -1.97223372919527, -1.97242384925416, + 0.97261396931306, 0.98621192462708], + [0.98500175787242, -1.96977855582618, -1.97000351574484, + 0.97022847566350, 0.98500175787242], + [0.97938932735214, -1.95835380975398, -1.95877865470428, + 0.95920349965459, 0.97938932735214], + [0.97531843204928, -1.95002759149878, -1.95063686409857, + 0.95124613669835, 0.97531843204928], + [0.97316523498161, -1.94561023566527, -1.94633046996323, + 0.94705070426118, 0.97316523498161], + [0.96454515552826, -1.92783286977036, -1.92909031105652, + 0.93034775234268, 0.96454515552826], + [0.96009142950541, -1.91858953033784, -1.92018285901082, + 0.92177618768381, 0.96009142950541], + [0.95856916599601, -1.91542108074780, -1.91713833199203, + 0.91885558323625, 0.95856916599601], + [0.94597685600279, -1.88903307939452, -1.89195371200558, + 0.89487434461664, 0.94597685600279]]; + + + /** + * When calling this procedure, make sure that ip[-order] and op[-order] + * point to real data + */ + //private void filterYule(final float[] input, int inputPos, float[] output, + //int outputPos, int nSamples, final float[] kernel) { + function filterYule(input, inputPos, output, outputPos, nSamples, kernel) { + + while ((nSamples--) != 0) { + /* 1e-10 is a hack to avoid slowdown because of denormals */ + output[outputPos] = 1e-10 + input[inputPos + 0] * kernel[0] + - output[outputPos - 1] * kernel[1] + input[inputPos - 1] + * kernel[2] - output[outputPos - 2] * kernel[3] + + input[inputPos - 2] * kernel[4] - output[outputPos - 3] + * kernel[5] + input[inputPos - 3] * kernel[6] + - output[outputPos - 4] * kernel[7] + input[inputPos - 4] + * kernel[8] - output[outputPos - 5] * kernel[9] + + input[inputPos - 5] * kernel[10] - output[outputPos - 6] + * kernel[11] + input[inputPos - 6] * kernel[12] + - output[outputPos - 7] * kernel[13] + input[inputPos - 7] + * kernel[14] - output[outputPos - 8] * kernel[15] + + input[inputPos - 8] * kernel[16] - output[outputPos - 9] + * kernel[17] + input[inputPos - 9] * kernel[18] + - output[outputPos - 10] * kernel[19] + + input[inputPos - 10] * kernel[20]; + ++outputPos; + ++inputPos; + } + } + +//private void filterButter(final float[] input, int inputPos, +// float[] output, int outputPos, int nSamples, final float[] kernel) { + function filterButter(input, inputPos, output, outputPos, nSamples, kernel) { + + while ((nSamples--) != 0) { + output[outputPos] = input[inputPos + 0] * kernel[0] + - output[outputPos - 1] * kernel[1] + input[inputPos - 1] + * kernel[2] - output[outputPos - 2] * kernel[3] + + input[inputPos - 2] * kernel[4]; + ++outputPos; + ++inputPos; + } + } + + /** + * @return INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if + * not + */ + function ResetSampleFrequency(rgData, samplefreq) { + /* zero out initial values */ + for (var i = 0; i < MAX_ORDER; i++) + rgData.linprebuf[i] = rgData.lstepbuf[i] = rgData.loutbuf[i] = rgData.rinprebuf[i] = rgData.rstepbuf[i] = rgData.routbuf[i] = 0.; + + switch (0 | (samplefreq)) { + case 48000: + rgData.reqindex = 0; + break; + case 44100: + rgData.reqindex = 1; + break; + case 32000: + rgData.reqindex = 2; + break; + case 24000: + rgData.reqindex = 3; + break; + case 22050: + rgData.reqindex = 4; + break; + case 16000: + rgData.reqindex = 5; + break; + case 12000: + rgData.reqindex = 6; + break; + case 11025: + rgData.reqindex = 7; + break; + case 8000: + rgData.reqindex = 8; + break; + default: + return INIT_GAIN_ANALYSIS_ERROR; + } + + rgData.sampleWindow = 0 | ((samplefreq * RMS_WINDOW_TIME_NUMERATOR + + RMS_WINDOW_TIME_DENOMINATOR - 1) / RMS_WINDOW_TIME_DENOMINATOR); + + rgData.lsum = 0.; + rgData.rsum = 0.; + rgData.totsamp = 0; + + Arrays.ill(rgData.A, 0); + + return INIT_GAIN_ANALYSIS_OK; + } + + this.InitGainAnalysis = function (rgData, samplefreq) { + if (ResetSampleFrequency(rgData, samplefreq) != INIT_GAIN_ANALYSIS_OK) { + return INIT_GAIN_ANALYSIS_ERROR; + } + + rgData.linpre = MAX_ORDER; + rgData.rinpre = MAX_ORDER; + rgData.lstep = MAX_ORDER; + rgData.rstep = MAX_ORDER; + rgData.lout = MAX_ORDER; + rgData.rout = MAX_ORDER; + + Arrays.fill(rgData.B, 0); + + return INIT_GAIN_ANALYSIS_OK; + }; + + /** + * square + */ + function fsqr(d) { + return d * d; + } + + this.AnalyzeSamples = function (rgData, left_samples, left_samplesPos, right_samples, right_samplesPos, num_samples, + num_channels) { + var curleft; + var curleftBase; + var curright; + var currightBase; + var batchsamples; + var cursamples; + var cursamplepos; + + if (num_samples == 0) + return GAIN_ANALYSIS_OK; + + cursamplepos = 0; + batchsamples = num_samples; + + switch (num_channels) { + case 1: + right_samples = left_samples; + right_samplesPos = left_samplesPos; + break; + case 2: + break; + default: + return GAIN_ANALYSIS_ERROR; + } + + if (num_samples < MAX_ORDER) { + System.arraycopy(left_samples, left_samplesPos, rgData.linprebuf, + MAX_ORDER, num_samples); + System.arraycopy(right_samples, right_samplesPos, rgData.rinprebuf, + MAX_ORDER, num_samples); + } else { + System.arraycopy(left_samples, left_samplesPos, rgData.linprebuf, + MAX_ORDER, MAX_ORDER); + System.arraycopy(right_samples, right_samplesPos, rgData.rinprebuf, + MAX_ORDER, MAX_ORDER); + } + + while (batchsamples > 0) { + cursamples = batchsamples > rgData.sampleWindow - rgData.totsamp ? rgData.sampleWindow + - rgData.totsamp + : batchsamples; + if (cursamplepos < MAX_ORDER) { + curleft = rgData.linpre + cursamplepos; + curleftBase = rgData.linprebuf; + curright = rgData.rinpre + cursamplepos; + currightBase = rgData.rinprebuf; + if (cursamples > MAX_ORDER - cursamplepos) + cursamples = MAX_ORDER - cursamplepos; + } else { + curleft = left_samplesPos + cursamplepos; + curleftBase = left_samples; + curright = right_samplesPos + cursamplepos; + currightBase = right_samples; + } + + filterYule(curleftBase, curleft, rgData.lstepbuf, rgData.lstep + + rgData.totsamp, cursamples, ABYule[rgData.reqindex]); + filterYule(currightBase, curright, rgData.rstepbuf, rgData.rstep + + rgData.totsamp, cursamples, ABYule[rgData.reqindex]); + + filterButter(rgData.lstepbuf, rgData.lstep + rgData.totsamp, + rgData.loutbuf, rgData.lout + rgData.totsamp, cursamples, + ABButter[rgData.reqindex]); + filterButter(rgData.rstepbuf, rgData.rstep + rgData.totsamp, + rgData.routbuf, rgData.rout + rgData.totsamp, cursamples, + ABButter[rgData.reqindex]); + + curleft = rgData.lout + rgData.totsamp; + /* Get the squared values */ + curleftBase = rgData.loutbuf; + curright = rgData.rout + rgData.totsamp; + currightBase = rgData.routbuf; + + var i = cursamples % 8; + while ((i--) != 0) { + rgData.lsum += fsqr(curleftBase[curleft++]); + rgData.rsum += fsqr(currightBase[curright++]); + } + i = cursamples / 8; + while ((i--) != 0) { + rgData.lsum += fsqr(curleftBase[curleft + 0]) + + fsqr(curleftBase[curleft + 1]) + + fsqr(curleftBase[curleft + 2]) + + fsqr(curleftBase[curleft + 3]) + + fsqr(curleftBase[curleft + 4]) + + fsqr(curleftBase[curleft + 5]) + + fsqr(curleftBase[curleft + 6]) + + fsqr(curleftBase[curleft + 7]); + curleft += 8; + rgData.rsum += fsqr(currightBase[curright + 0]) + + fsqr(currightBase[curright + 1]) + + fsqr(currightBase[curright + 2]) + + fsqr(currightBase[curright + 3]) + + fsqr(currightBase[curright + 4]) + + fsqr(currightBase[curright + 5]) + + fsqr(currightBase[curright + 6]) + + fsqr(currightBase[curright + 7]); + curright += 8; + } + + batchsamples -= cursamples; + cursamplepos += cursamples; + rgData.totsamp += cursamples; + if (rgData.totsamp == rgData.sampleWindow) { + /* Get the Root Mean Square (RMS) for this set of samples */ + var val = GainAnalysis.STEPS_per_dB + * 10. + * Math.log10((rgData.lsum + rgData.rsum) + / rgData.totsamp * 0.5 + 1.e-37); + var ival = (val <= 0) ? 0 : 0 | val; + if (ival >= rgData.A.length) + ival = rgData.A.length - 1; + rgData.A[ival]++; + rgData.lsum = rgData.rsum = 0.; + + System.arraycopy(rgData.loutbuf, rgData.totsamp, + rgData.loutbuf, 0, MAX_ORDER); + System.arraycopy(rgData.routbuf, rgData.totsamp, + rgData.routbuf, 0, MAX_ORDER); + System.arraycopy(rgData.lstepbuf, rgData.totsamp, + rgData.lstepbuf, 0, MAX_ORDER); + System.arraycopy(rgData.rstepbuf, rgData.totsamp, + rgData.rstepbuf, 0, MAX_ORDER); + rgData.totsamp = 0; + } + if (rgData.totsamp > rgData.sampleWindow) { + /* + * somehow I really screwed up: Error in programming! Contact + * author about totsamp > sampleWindow + */ + return GAIN_ANALYSIS_ERROR; + } + } + if (num_samples < MAX_ORDER) { + System.arraycopy(rgData.linprebuf, num_samples, rgData.linprebuf, + 0, MAX_ORDER - num_samples); + System.arraycopy(rgData.rinprebuf, num_samples, rgData.rinprebuf, + 0, MAX_ORDER - num_samples); + System.arraycopy(left_samples, left_samplesPos, rgData.linprebuf, + MAX_ORDER - num_samples, num_samples); + System.arraycopy(right_samples, right_samplesPos, rgData.rinprebuf, + MAX_ORDER - num_samples, num_samples); + } else { + System.arraycopy(left_samples, left_samplesPos + num_samples + - MAX_ORDER, rgData.linprebuf, 0, MAX_ORDER); + System.arraycopy(right_samples, right_samplesPos + num_samples + - MAX_ORDER, rgData.rinprebuf, 0, MAX_ORDER); + } + + return GAIN_ANALYSIS_OK; + }; + + function analyzeResult(Array, len) { + var i; + + var elems = 0; + for (i = 0; i < len; i++) + elems += Array[i]; + if (elems == 0) + return GAIN_NOT_ENOUGH_SAMPLES; + + var upper = 0 | Math.ceil(elems * (1. - RMS_PERCENTILE)); + for (i = len; i-- > 0;) { + if ((upper -= Array[i]) <= 0) + break; + } + + //return (float) ((float) PINK_REF - (float) i / (float) STEPS_per_dB); + return (PINK_REF - i / GainAnalysis.STEPS_per_dB); + } + + this.GetTitleGain = function (rgData) { + var retval = analyzeResult(rgData.A, rgData.A.length); + + for (var i = 0; i < rgData.A.length; i++) { + rgData.B[i] += rgData.A[i]; + rgData.A[i] = 0; + } + + for (var i = 0; i < MAX_ORDER; i++) + rgData.linprebuf[i] = rgData.lstepbuf[i] = rgData.loutbuf[i] = rgData.rinprebuf[i] = rgData.rstepbuf[i] = rgData.routbuf[i] = 0.; + + rgData.totsamp = 0; + rgData.lsum = rgData.rsum = 0.; + return retval; + } + +} + + +function Presets() { + function VBRPresets(qual, comp, compS, + y, shThreshold, shThresholdS, + adj, adjShort, lower, + curve, sens, inter, + joint, mod, fix) { + this.vbr_q = qual; + this.quant_comp = comp; + this.quant_comp_s = compS; + this.expY = y; + this.st_lrm = shThreshold; + this.st_s = shThresholdS; + this.masking_adj = adj; + this.masking_adj_short = adjShort; + this.ath_lower = lower; + this.ath_curve = curve; + this.ath_sensitivity = sens; + this.interch = inter; + this.safejoint = joint; + this.sfb21mod = mod; + this.msfix = fix; + } + + function ABRPresets(kbps, comp, compS, + joint, fix, shThreshold, + shThresholdS, bass, sc, + mask, lower, curve, + interCh, sfScale) { + this.quant_comp = comp; + this.quant_comp_s = compS; + this.safejoint = joint; + this.nsmsfix = fix; + this.st_lrm = shThreshold; + this.st_s = shThresholdS; + this.nsbass = bass; + this.scale = sc; + this.masking_adj = mask; + this.ath_lower = lower; + this.ath_curve = curve; + this.interch = interCh; + this.sfscale = sfScale; + } + + var lame; + + this.setModules = function (_lame) { + lame = _lame; + }; + + /** + *
+     * Switch mappings for VBR mode VBR_RH
+     *             vbr_q  qcomp_l  qcomp_s  expY  st_lrm   st_s  mask adj_l  adj_s  ath_lower  ath_curve  ath_sens  interChR  safejoint sfb21mod  msfix
+     * 
+ */ + var vbr_old_switch_map = [ + new VBRPresets(0, 9, 9, 0, 5.20, 125.0, -4.2, -6.3, 4.8, 1, 0, 0, 2, 21, 0.97), + new VBRPresets(1, 9, 9, 0, 5.30, 125.0, -3.6, -5.6, 4.5, 1.5, 0, 0, 2, 21, 1.35), + new VBRPresets(2, 9, 9, 0, 5.60, 125.0, -2.2, -3.5, 2.8, 2, 0, 0, 2, 21, 1.49), + new VBRPresets(3, 9, 9, 1, 5.80, 130.0, -1.8, -2.8, 2.6, 3, -4, 0, 2, 20, 1.64), + new VBRPresets(4, 9, 9, 1, 6.00, 135.0, -0.7, -1.1, 1.1, 3.5, -8, 0, 2, 0, 1.79), + new VBRPresets(5, 9, 9, 1, 6.40, 140.0, 0.5, 0.4, -7.5, 4, -12, 0.0002, 0, 0, 1.95), + new VBRPresets(6, 9, 9, 1, 6.60, 145.0, 0.67, 0.65, -14.7, 6.5, -19, 0.0004, 0, 0, 2.30), + new VBRPresets(7, 9, 9, 1, 6.60, 145.0, 0.8, 0.75, -19.7, 8, -22, 0.0006, 0, 0, 2.70), + new VBRPresets(8, 9, 9, 1, 6.60, 145.0, 1.2, 1.15, -27.5, 10, -23, 0.0007, 0, 0, 0), + new VBRPresets(9, 9, 9, 1, 6.60, 145.0, 1.6, 1.6, -36, 11, -25, 0.0008, 0, 0, 0), + new VBRPresets(10, 9, 9, 1, 6.60, 145.0, 2.0, 2.0, -36, 12, -25, 0.0008, 0, 0, 0) + ]; + + /** + *
+     *                 vbr_q  qcomp_l  qcomp_s  expY  st_lrm   st_s  mask adj_l  adj_s  ath_lower  ath_curve  ath_sens  interChR  safejoint sfb21mod  msfix
+     * 
+ */ + var vbr_psy_switch_map = [ + new VBRPresets(0, 9, 9, 0, 4.20, 25.0, -7.0, -4.0, 7.5, 1, 0, 0, 2, 26, 0.97), + new VBRPresets(1, 9, 9, 0, 4.20, 25.0, -5.6, -3.6, 4.5, 1.5, 0, 0, 2, 21, 1.35), + new VBRPresets(2, 9, 9, 0, 4.20, 25.0, -4.4, -1.8, 2, 2, 0, 0, 2, 18, 1.49), + new VBRPresets(3, 9, 9, 1, 4.20, 25.0, -3.4, -1.25, 1.1, 3, -4, 0, 2, 15, 1.64), + new VBRPresets(4, 9, 9, 1, 4.20, 25.0, -2.2, 0.1, 0, 3.5, -8, 0, 2, 0, 1.79), + new VBRPresets(5, 9, 9, 1, 4.20, 25.0, -1.0, 1.65, -7.7, 4, -12, 0.0002, 0, 0, 1.95), + new VBRPresets(6, 9, 9, 1, 4.20, 25.0, -0.0, 2.47, -7.7, 6.5, -19, 0.0004, 0, 0, 2), + new VBRPresets(7, 9, 9, 1, 4.20, 25.0, 0.5, 2.0, -14.5, 8, -22, 0.0006, 0, 0, 2), + new VBRPresets(8, 9, 9, 1, 4.20, 25.0, 1.0, 2.4, -22.0, 10, -23, 0.0007, 0, 0, 2), + new VBRPresets(9, 9, 9, 1, 4.20, 25.0, 1.5, 2.95, -30.0, 11, -25, 0.0008, 0, 0, 2), + new VBRPresets(10, 9, 9, 1, 4.20, 25.0, 2.0, 2.95, -36.0, 12, -30, 0.0008, 0, 0, 2) + ]; + + function apply_vbr_preset(gfp, a, enforce) { + var vbr_preset = gfp.VBR == VbrMode.vbr_rh ? vbr_old_switch_map + : vbr_psy_switch_map; + + var x = gfp.VBR_q_frac; + var p = vbr_preset[a]; + var q = vbr_preset[a + 1]; + var set = p; + + // NOOP(vbr_q); + // NOOP(quant_comp); + // NOOP(quant_comp_s); + // NOOP(expY); + p.st_lrm = p.st_lrm + x * (q.st_lrm - p.st_lrm); + // LERP(st_lrm); + p.st_s = p.st_s + x * (q.st_s - p.st_s); + // LERP(st_s); + p.masking_adj = p.masking_adj + x * (q.masking_adj - p.masking_adj); + // LERP(masking_adj); + p.masking_adj_short = p.masking_adj_short + x + * (q.masking_adj_short - p.masking_adj_short); + // LERP(masking_adj_short); + p.ath_lower = p.ath_lower + x * (q.ath_lower - p.ath_lower); + // LERP(ath_lower); + p.ath_curve = p.ath_curve + x * (q.ath_curve - p.ath_curve); + // LERP(ath_curve); + p.ath_sensitivity = p.ath_sensitivity + x + * (q.ath_sensitivity - p.ath_sensitivity); + // LERP(ath_sensitivity); + p.interch = p.interch + x * (q.interch - p.interch); + // LERP(interch); + // NOOP(safejoint); + // NOOP(sfb21mod); + p.msfix = p.msfix + x * (q.msfix - p.msfix); + // LERP(msfix); + + lame_set_VBR_q(gfp, set.vbr_q); + + if (enforce != 0) + gfp.quant_comp = set.quant_comp; + else if (!(Math.abs(gfp.quant_comp - -1) > 0)) + gfp.quant_comp = set.quant_comp; + // SET_OPTION(quant_comp, set.quant_comp, -1); + if (enforce != 0) + gfp.quant_comp_short = set.quant_comp_s; + else if (!(Math.abs(gfp.quant_comp_short - -1) > 0)) + gfp.quant_comp_short = set.quant_comp_s; + // SET_OPTION(quant_comp_short, set.quant_comp_s, -1); + if (set.expY != 0) { + gfp.experimentalY = set.expY != 0; + } + if (enforce != 0) + gfp.internal_flags.nsPsy.attackthre = set.st_lrm; + else if (!(Math.abs(gfp.internal_flags.nsPsy.attackthre - -1) > 0)) + gfp.internal_flags.nsPsy.attackthre = set.st_lrm; + // SET_OPTION(short_threshold_lrm, set.st_lrm, -1); + if (enforce != 0) + gfp.internal_flags.nsPsy.attackthre_s = set.st_s; + else if (!(Math.abs(gfp.internal_flags.nsPsy.attackthre_s - -1) > 0)) + gfp.internal_flags.nsPsy.attackthre_s = set.st_s; + // SET_OPTION(short_threshold_s, set.st_s, -1); + if (enforce != 0) + gfp.maskingadjust = set.masking_adj; + else if (!(Math.abs(gfp.maskingadjust - 0) > 0)) + gfp.maskingadjust = set.masking_adj; + // SET_OPTION(maskingadjust, set.masking_adj, 0); + if (enforce != 0) + gfp.maskingadjust_short = set.masking_adj_short; + else if (!(Math.abs(gfp.maskingadjust_short - 0) > 0)) + gfp.maskingadjust_short = set.masking_adj_short; + // SET_OPTION(maskingadjust_short, set.masking_adj_short, 0); + if (enforce != 0) + gfp.ATHlower = -set.ath_lower / 10.0; + else if (!(Math.abs((-gfp.ATHlower * 10.0) - 0) > 0)) + gfp.ATHlower = -set.ath_lower / 10.0; + // SET_OPTION(ATHlower, set.ath_lower, 0); + if (enforce != 0) + gfp.ATHcurve = set.ath_curve; + else if (!(Math.abs(gfp.ATHcurve - -1) > 0)) + gfp.ATHcurve = set.ath_curve; + // SET_OPTION(ATHcurve, set.ath_curve, -1); + if (enforce != 0) + gfp.athaa_sensitivity = set.ath_sensitivity; + else if (!(Math.abs(gfp.athaa_sensitivity - -1) > 0)) + gfp.athaa_sensitivity = set.ath_sensitivity; + // SET_OPTION(athaa_sensitivity, set.ath_sensitivity, 0); + if (set.interch > 0) { + if (enforce != 0) + gfp.interChRatio = set.interch; + else if (!(Math.abs(gfp.interChRatio - -1) > 0)) + gfp.interChRatio = set.interch; + // SET_OPTION(interChRatio, set.interch, -1); + } + + /* parameters for which there is no proper set/get interface */ + if (set.safejoint > 0) { + gfp.exp_nspsytune = gfp.exp_nspsytune | set.safejoint; + } + if (set.sfb21mod > 0) { + gfp.exp_nspsytune = gfp.exp_nspsytune | (set.sfb21mod << 20); + } + if (enforce != 0) + gfp.msfix = set.msfix; + else if (!(Math.abs(gfp.msfix - -1) > 0)) + gfp.msfix = set.msfix; + // SET_OPTION(msfix, set.msfix, -1); + + if (enforce == 0) { + gfp.VBR_q = a; + gfp.VBR_q_frac = x; + } + } + + /** + *
+     *  Switch mappings for ABR mode
+     *
+     *              kbps  quant q_s safejoint nsmsfix st_lrm  st_s  ns-bass scale   msk ath_lwr ath_curve  interch , sfscale
+     * 
+ */ + var abr_switch_map = [ + new ABRPresets(8, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -30.0, 11, 0.0012, 1), /* 8, impossible to use in stereo */ + new ABRPresets(16, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -25.0, 11, 0.0010, 1), /* 16 */ + new ABRPresets(24, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -20.0, 11, 0.0010, 1), /* 24 */ + new ABRPresets(32, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -15.0, 11, 0.0010, 1), /* 32 */ + new ABRPresets(40, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -10.0, 11, 0.0009, 1), /* 40 */ + new ABRPresets(48, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -10.0, 11, 0.0009, 1), /* 48 */ + new ABRPresets(56, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -6.0, 11, 0.0008, 1), /* 56 */ + new ABRPresets(64, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, -2.0, 11, 0.0008, 1), /* 64 */ + new ABRPresets(80, 9, 9, 0, 0, 6.60, 145, 0, 0.95, 0, .0, 8, 0.0007, 1), /* 80 */ + new ABRPresets(96, 9, 9, 0, 2.50, 6.60, 145, 0, 0.95, 0, 1.0, 5.5, 0.0006, 1), /* 96 */ + new ABRPresets(112, 9, 9, 0, 2.25, 6.60, 145, 0, 0.95, 0, 2.0, 4.5, 0.0005, 1), /* 112 */ + new ABRPresets(128, 9, 9, 0, 1.95, 6.40, 140, 0, 0.95, 0, 3.0, 4, 0.0002, 1), /* 128 */ + new ABRPresets(160, 9, 9, 1, 1.79, 6.00, 135, 0, 0.95, -2, 5.0, 3.5, 0, 1), /* 160 */ + new ABRPresets(192, 9, 9, 1, 1.49, 5.60, 125, 0, 0.97, -4, 7.0, 3, 0, 0), /* 192 */ + new ABRPresets(224, 9, 9, 1, 1.25, 5.20, 125, 0, 0.98, -6, 9.0, 2, 0, 0), /* 224 */ + new ABRPresets(256, 9, 9, 1, 0.97, 5.20, 125, 0, 1.00, -8, 10.0, 1, 0, 0), /* 256 */ + new ABRPresets(320, 9, 9, 1, 0.90, 5.20, 125, 0, 1.00, -10, 12.0, 0, 0, 0) /* 320 */ + ]; + + function apply_abr_preset(gfp, preset, enforce) { + /* Variables for the ABR stuff */ + var actual_bitrate = preset; + + var r = lame.nearestBitrateFullIndex(preset); + + gfp.VBR = VbrMode.vbr_abr; + gfp.VBR_mean_bitrate_kbps = actual_bitrate; + gfp.VBR_mean_bitrate_kbps = Math.min(gfp.VBR_mean_bitrate_kbps, 320); + gfp.VBR_mean_bitrate_kbps = Math.max(gfp.VBR_mean_bitrate_kbps, 8); + gfp.brate = gfp.VBR_mean_bitrate_kbps; + if (gfp.VBR_mean_bitrate_kbps > 320) { + gfp.disable_reservoir = true; + } + + /* parameters for which there is no proper set/get interface */ + if (abr_switch_map[r].safejoint > 0) + gfp.exp_nspsytune = gfp.exp_nspsytune | 2; + /* safejoint */ + + if (abr_switch_map[r].sfscale > 0) { + gfp.internal_flags.noise_shaping = 2; + } + /* ns-bass tweaks */ + if (Math.abs(abr_switch_map[r].nsbass) > 0) { + var k = (int)(abr_switch_map[r].nsbass * 4); + if (k < 0) + k += 64; + gfp.exp_nspsytune = gfp.exp_nspsytune | (k << 2); + } + + if (enforce != 0) + gfp.quant_comp = abr_switch_map[r].quant_comp; + else if (!(Math.abs(gfp.quant_comp - -1) > 0)) + gfp.quant_comp = abr_switch_map[r].quant_comp; + // SET_OPTION(quant_comp, abr_switch_map[r].quant_comp, -1); + if (enforce != 0) + gfp.quant_comp_short = abr_switch_map[r].quant_comp_s; + else if (!(Math.abs(gfp.quant_comp_short - -1) > 0)) + gfp.quant_comp_short = abr_switch_map[r].quant_comp_s; + // SET_OPTION(quant_comp_short, abr_switch_map[r].quant_comp_s, -1); + + if (enforce != 0) + gfp.msfix = abr_switch_map[r].nsmsfix; + else if (!(Math.abs(gfp.msfix - -1) > 0)) + gfp.msfix = abr_switch_map[r].nsmsfix; + // SET_OPTION(msfix, abr_switch_map[r].nsmsfix, -1); + + if (enforce != 0) + gfp.internal_flags.nsPsy.attackthre = abr_switch_map[r].st_lrm; + else if (!(Math.abs(gfp.internal_flags.nsPsy.attackthre - -1) > 0)) + gfp.internal_flags.nsPsy.attackthre = abr_switch_map[r].st_lrm; + // SET_OPTION(short_threshold_lrm, abr_switch_map[r].st_lrm, -1); + if (enforce != 0) + gfp.internal_flags.nsPsy.attackthre_s = abr_switch_map[r].st_s; + else if (!(Math.abs(gfp.internal_flags.nsPsy.attackthre_s - -1) > 0)) + gfp.internal_flags.nsPsy.attackthre_s = abr_switch_map[r].st_s; + // SET_OPTION(short_threshold_s, abr_switch_map[r].st_s, -1); + + /* + * ABR seems to have big problems with clipping, especially at low + * bitrates + */ + /* + * so we compensate for that here by using a scale value depending on + * bitrate + */ + if (enforce != 0) + gfp.scale = abr_switch_map[r].scale; + else if (!(Math.abs(gfp.scale - -1) > 0)) + gfp.scale = abr_switch_map[r].scale; + // SET_OPTION(scale, abr_switch_map[r].scale, -1); + + if (enforce != 0) + gfp.maskingadjust = abr_switch_map[r].masking_adj; + else if (!(Math.abs(gfp.maskingadjust - 0) > 0)) + gfp.maskingadjust = abr_switch_map[r].masking_adj; + // SET_OPTION(maskingadjust, abr_switch_map[r].masking_adj, 0); + if (abr_switch_map[r].masking_adj > 0) { + if (enforce != 0) + gfp.maskingadjust_short = (abr_switch_map[r].masking_adj * .9); + else if (!(Math.abs(gfp.maskingadjust_short - 0) > 0)) + gfp.maskingadjust_short = (abr_switch_map[r].masking_adj * .9); + // SET_OPTION(maskingadjust_short, abr_switch_map[r].masking_adj * + // .9, 0); + } else { + if (enforce != 0) + gfp.maskingadjust_short = (abr_switch_map[r].masking_adj * 1.1); + else if (!(Math.abs(gfp.maskingadjust_short - 0) > 0)) + gfp.maskingadjust_short = (abr_switch_map[r].masking_adj * 1.1); + // SET_OPTION(maskingadjust_short, abr_switch_map[r].masking_adj * + // 1.1, 0); + } + + if (enforce != 0) + gfp.ATHlower = -abr_switch_map[r].ath_lower / 10.; + else if (!(Math.abs((-gfp.ATHlower * 10.) - 0) > 0)) + gfp.ATHlower = -abr_switch_map[r].ath_lower / 10.; + // SET_OPTION(ATHlower, abr_switch_map[r].ath_lower, 0); + if (enforce != 0) + gfp.ATHcurve = abr_switch_map[r].ath_curve; + else if (!(Math.abs(gfp.ATHcurve - -1) > 0)) + gfp.ATHcurve = abr_switch_map[r].ath_curve; + // SET_OPTION(ATHcurve, abr_switch_map[r].ath_curve, -1); + + if (enforce != 0) + gfp.interChRatio = abr_switch_map[r].interch; + else if (!(Math.abs(gfp.interChRatio - -1) > 0)) + gfp.interChRatio = abr_switch_map[r].interch; + // SET_OPTION(interChRatio, abr_switch_map[r].interch, -1); + + return preset; + } + + this.apply_preset = function(gfp, preset, enforce) { + /* translate legacy presets */ + switch (preset) { + case Lame.R3MIX: + { + preset = Lame.V3; + gfp.VBR = VbrMode.vbr_mtrh; + break; + } + case Lame.MEDIUM: + { + preset = Lame.V4; + gfp.VBR = VbrMode.vbr_rh; + break; + } + case Lame.MEDIUM_FAST: + { + preset = Lame.V4; + gfp.VBR = VbrMode.vbr_mtrh; + break; + } + case Lame.STANDARD: + { + preset = Lame.V2; + gfp.VBR = VbrMode.vbr_rh; + break; + } + case Lame.STANDARD_FAST: + { + preset = Lame.V2; + gfp.VBR = VbrMode.vbr_mtrh; + break; + } + case Lame.EXTREME: + { + preset = Lame.V0; + gfp.VBR = VbrMode.vbr_rh; + break; + } + case Lame.EXTREME_FAST: + { + preset = Lame.V0; + gfp.VBR = VbrMode.vbr_mtrh; + break; + } + case Lame.INSANE: + { + preset = 320; + gfp.preset = preset; + apply_abr_preset(gfp, preset, enforce); + gfp.VBR = VbrMode.vbr_off; + return preset; + } + } + + gfp.preset = preset; + { + switch (preset) { + case Lame.V9: + apply_vbr_preset(gfp, 9, enforce); + return preset; + case Lame.V8: + apply_vbr_preset(gfp, 8, enforce); + return preset; + case Lame.V7: + apply_vbr_preset(gfp, 7, enforce); + return preset; + case Lame.V6: + apply_vbr_preset(gfp, 6, enforce); + return preset; + case Lame.V5: + apply_vbr_preset(gfp, 5, enforce); + return preset; + case Lame.V4: + apply_vbr_preset(gfp, 4, enforce); + return preset; + case Lame.V3: + apply_vbr_preset(gfp, 3, enforce); + return preset; + case Lame.V2: + apply_vbr_preset(gfp, 2, enforce); + return preset; + case Lame.V1: + apply_vbr_preset(gfp, 1, enforce); + return preset; + case Lame.V0: + apply_vbr_preset(gfp, 0, enforce); + return preset; + default: + break; + } + } + if (8 <= preset && preset <= 320) { + return apply_abr_preset(gfp, preset, enforce); + } + + /* no corresponding preset found */ + gfp.preset = 0; + return preset; + } + + // Rest from getset.c: + + /** + * VBR quality level.
+ * 0 = highest
+ * 9 = lowest + */ + function lame_set_VBR_q(gfp, VBR_q) { + var ret = 0; + + if (0 > VBR_q) { + /* Unknown VBR quality level! */ + ret = -1; + VBR_q = 0; + } + if (9 < VBR_q) { + ret = -1; + VBR_q = 9; + } + + gfp.VBR_q = VBR_q; + gfp.VBR_q_frac = 0; + return ret; + } + +} + +/* + * bit reservoir source file + * + * Copyright (c) 1999-2000 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: Reservoir.java,v 1.9 2011/05/24 20:48:06 kenchis Exp $ */ + +//package mp3; + +/** + * ResvFrameBegin:
+ * Called (repeatedly) at the beginning of a frame. Updates the maximum size of + * the reservoir, and checks to make sure main_data_begin was set properly by + * the formatter
+ * Background information: + * + * This is the original text from the ISO standard. Because of sooo many bugs + * and irritations correcting comments are added in brackets []. A '^W' means + * you should remove the last word. + * + *
+ *  1. The following rule can be used to calculate the maximum
+ *     number of bits used for one granule [^W frame]:
+ * At the highest possible bitrate of Layer III (320 kbps + * per stereo signal [^W^W^W], 48 kHz) the frames must be of + * [^W^W^W are designed to have] constant length, i.e. + * one buffer [^W^W the frame] length is:
+ * + * 320 kbps * 1152/48 kHz = 7680 bit = 960 byte + * + * This value is used as the maximum buffer per channel [^W^W] at + * lower bitrates [than 320 kbps]. At 64 kbps mono or 128 kbps + * stereo the main granule length is 64 kbps * 576/48 kHz = 768 bit + * [per granule and channel] at 48 kHz sampling frequency. + * This means that there is a maximum deviation (short time buffer + * [= reservoir]) of 7680 - 2*2*768 = 4608 bits is allowed at 64 kbps. + * The actual deviation is equal to the number of bytes [with the + * meaning of octets] denoted by the main_data_end offset pointer. + * The actual maximum deviation is (2^9-1)*8 bit = 4088 bits + * [for MPEG-1 and (2^8-1)*8 bit for MPEG-2, both are hard limits]. + * ... The xchange of buffer bits between the left and right channel + * is allowed without restrictions [exception: dual channel]. + * Because of the [constructed] constraint on the buffer size + * main_data_end is always set to 0 in the case of bit_rate_index==14, + * i.e. data rate 320 kbps per stereo signal [^W^W^W]. In this case + * all data are allocated between adjacent header [^W sync] words + * [, i.e. there is no buffering at all]. + *
+ */ + + +function Reservoir() { + var bs; + + this.setModules = function(_bs) { + bs = _bs; + } + + this.ResvFrameBegin = function(gfp, mean_bits) { + var gfc = gfp.internal_flags; + var maxmp3buf; + var l3_side = gfc.l3_side; + + var frameLength = bs.getframebits(gfp); + mean_bits.bits = (frameLength - gfc.sideinfo_len * 8) / gfc.mode_gr; + + /** + *
+		 *  Meaning of the variables:
+		 *      resvLimit: (0, 8, ..., 8*255 (MPEG-2), 8*511 (MPEG-1))
+		 *          Number of bits can be stored in previous frame(s) due to
+		 *          counter size constaints
+		 *      maxmp3buf: ( ??? ... 8*1951 (MPEG-1 and 2), 8*2047 (MPEG-2.5))
+		 *          Number of bits allowed to encode one frame (you can take 8*511 bit
+		 *          from the bit reservoir and at most 8*1440 bit from the current
+		 *          frame (320 kbps, 32 kHz), so 8*1951 bit is the largest possible
+		 *          value for MPEG-1 and -2)
+		 * 
+		 *          maximum allowed granule/channel size times 4 = 8*2047 bits.,
+		 *          so this is the absolute maximum supported by the format.
+		 * 
+		 * 
+		 *      fullFrameBits:  maximum number of bits available for encoding
+		 *                      the current frame.
+		 * 
+		 *      mean_bits:      target number of bits per granule.
+		 * 
+		 *      frameLength:
+		 * 
+		 *      gfc.ResvMax:   maximum allowed reservoir
+		 * 
+		 *      gfc.ResvSize:  current reservoir size
+		 * 
+		 *      l3_side.resvDrain_pre:
+		 *         ancillary data to be added to previous frame:
+		 *         (only usefull in VBR modes if it is possible to have
+		 *         maxmp3buf < fullFrameBits)).  Currently disabled,
+		 *         see #define NEW_DRAIN
+		 *         2010-02-13: RH now enabled, it seems to be needed for CBR too,
+		 *                     as there exists one example, where the FhG decoder
+		 *                     can't decode a -b320 CBR file anymore.
+		 * 
+		 *      l3_side.resvDrain_post:
+		 *         ancillary data to be added to this frame:
+		 * 
+		 * 
+ */ + + /* main_data_begin has 9 bits in MPEG-1, 8 bits MPEG-2 */ + var resvLimit = (8 * 256) * gfc.mode_gr - 8; + + /* + * maximum allowed frame size. dont use more than this number of bits, + * even if the frame has the space for them: + */ + if (gfp.brate > 320) { + /* in freeformat the buffer is constant */ + maxmp3buf = 8 * ((int) ((gfp.brate * 1000) + / (gfp.out_samplerate / 1152) / 8 + .5)); + } else { + /* + * all mp3 decoders should have enough buffer to handle this value: + * size of a 320kbps 32kHz frame + */ + maxmp3buf = 8 * 1440; + + /* + * Bouvigne suggests this more lax interpretation of the ISO doc + * instead of using 8*960. + */ + + if (gfp.strict_ISO) { + maxmp3buf = 8 * ((int) (320000 / (gfp.out_samplerate / 1152) / 8 + .5)); + } + } + + gfc.ResvMax = maxmp3buf - frameLength; + if (gfc.ResvMax > resvLimit) + gfc.ResvMax = resvLimit; + if (gfc.ResvMax < 0 || gfp.disable_reservoir) + gfc.ResvMax = 0; + + var fullFrameBits = mean_bits.bits * gfc.mode_gr + + Math.min(gfc.ResvSize, gfc.ResvMax); + + if (fullFrameBits > maxmp3buf) + fullFrameBits = maxmp3buf; + + + l3_side.resvDrain_pre = 0; + + // frame analyzer code + if (gfc.pinfo != null) { + /* + * expected bits per channel per granule [is this also right for + * mono/stereo, MPEG-1/2 ?] + */ + gfc.pinfo.mean_bits = mean_bits.bits / 2; + gfc.pinfo.resvsize = gfc.ResvSize; + } + + return fullFrameBits; + } + + /** + * returns targ_bits: target number of bits to use for 1 granule
+ * extra_bits: amount extra available from reservoir
+ * Mark Taylor 4/99 + */ + this.ResvMaxBits = function(gfp, mean_bits, targ_bits, cbr) { + var gfc = gfp.internal_flags; + var add_bits; + var ResvSize = gfc.ResvSize, ResvMax = gfc.ResvMax; + + /* compensate the saved bits used in the 1st granule */ + if (cbr != 0) + ResvSize += mean_bits; + + if ((gfc.substep_shaping & 1) != 0) + ResvMax *= 0.9; + + targ_bits.bits = mean_bits; + + /* extra bits if the reservoir is almost full */ + if (ResvSize * 10 > ResvMax * 9) { + add_bits = ResvSize - (ResvMax * 9) / 10; + targ_bits.bits += add_bits; + gfc.substep_shaping |= 0x80; + } else { + add_bits = 0; + gfc.substep_shaping &= 0x7f; + /* + * build up reservoir. this builds the reservoir a little slower + * than FhG. It could simple be mean_bits/15, but this was rigged to + * always produce 100 (the old value) at 128kbs + */ + if (!gfp.disable_reservoir && 0 == (gfc.substep_shaping & 1)) + targ_bits.bits -= .1 * mean_bits; + } + + /* amount from the reservoir we are allowed to use. ISO says 6/10 */ + var extra_bits = (ResvSize < (gfc.ResvMax * 6) / 10 ? ResvSize + : (gfc.ResvMax * 6) / 10); + extra_bits -= add_bits; + + if (extra_bits < 0) + extra_bits = 0; + return extra_bits; + } + + /** + * Called after a granule's bit allocation. Readjusts the size of the + * reservoir to reflect the granule's usage. + */ + this.ResvAdjust = function(gfc, gi) { + gfc.ResvSize -= gi.part2_3_length + gi.part2_length; + } + + /** + * Called after all granules in a frame have been allocated. Makes sure that + * the reservoir size is within limits, possibly by adding stuffing bits. + */ + this.ResvFrameEnd = function(gfc, mean_bits) { + var over_bits; + var l3_side = gfc.l3_side; + + gfc.ResvSize += mean_bits * gfc.mode_gr; + var stuffingBits = 0; + l3_side.resvDrain_post = 0; + l3_side.resvDrain_pre = 0; + + /* we must be byte aligned */ + if ((over_bits = gfc.ResvSize % 8) != 0) + stuffingBits += over_bits; + + over_bits = (gfc.ResvSize - stuffingBits) - gfc.ResvMax; + if (over_bits > 0) { + stuffingBits += over_bits; + } + + /* + * NOTE: enabling the NEW_DRAIN code fixes some problems with FhG + * decoder shipped with MS Windows operating systems. Using this, it is + * even possible to use Gabriel's lax buffer consideration again, which + * assumes, any decoder should have a buffer large enough for a 320 kbps + * frame at 32 kHz sample rate. + * + * old drain code: lame -b320 BlackBird.wav --. does not play with + * GraphEdit.exe using FhG decoder V1.5 Build 50 + * + * new drain code: lame -b320 BlackBird.wav --. plays fine with + * GraphEdit.exe using FhG decoder V1.5 Build 50 + * + * Robert Hegemann, 2010-02-13. + */ + /* + * drain as many bits as possible into previous frame ancillary data In + * particular, in VBR mode ResvMax may have changed, and we have to make + * sure main_data_begin does not create a reservoir bigger than ResvMax + * mt 4/00 + */ + { + var mdb_bytes = Math.min(l3_side.main_data_begin * 8, stuffingBits) / 8; + l3_side.resvDrain_pre += 8 * mdb_bytes; + stuffingBits -= 8 * mdb_bytes; + gfc.ResvSize -= 8 * mdb_bytes; + l3_side.main_data_begin -= mdb_bytes; + } + /* drain the rest into this frames ancillary data */ + l3_side.resvDrain_post += stuffingBits; + gfc.ResvSize -= stuffingBits; + } +} + + +/** + * A Vbr header may be present in the ancillary data field of the first frame of + * an mp3 bitstream
+ * The Vbr header (optionally) contains + *
    + *
  • frames total number of audio frames in the bitstream + *
  • bytes total number of bytes in the bitstream + *
  • toc table of contents + *
+ * + * toc (table of contents) gives seek points for random access.
+ * The ith entry determines the seek point for i-percent duration.
+ * seek point in bytes = (toc[i]/256.0) * total_bitstream_bytes
+ * e.g. half duration seek point = (toc[50]/256.0) * total_bitstream_bytes + */ +VBRTag.NUMTOCENTRIES = 100; +VBRTag.MAXFRAMESIZE = 2880; + +function VBRTag() { + + var lame; + var bs; + var v; + + this.setModules = function (_lame, _bs, _v) { + lame = _lame; + bs = _bs; + v = _v; + }; + + var FRAMES_FLAG = 0x0001; + var BYTES_FLAG = 0x0002; + var TOC_FLAG = 0x0004; + var VBR_SCALE_FLAG = 0x0008; + + var NUMTOCENTRIES = VBRTag.NUMTOCENTRIES; + + /** + * (0xB40) the max freeformat 640 32kHz framesize. + */ + var MAXFRAMESIZE = VBRTag.MAXFRAMESIZE; + + /** + *
+     *    4 bytes for Header Tag
+     *    4 bytes for Header Flags
+     *  100 bytes for entry (toc)
+     *    4 bytes for frame size
+     *    4 bytes for stream size
+     *    4 bytes for VBR scale. a VBR quality indicator: 0=best 100=worst
+     *   20 bytes for LAME tag.  for example, "LAME3.12 (beta 6)"
+     * ___________
+     *  140 bytes
+     * 
+ */ + var VBRHEADERSIZE = (NUMTOCENTRIES + 4 + 4 + 4 + 4 + 4); + + var LAMEHEADERSIZE = (VBRHEADERSIZE + 9 + 1 + 1 + 8 + + 1 + 1 + 3 + 1 + 1 + 2 + 4 + 2 + 2); + + /** + * The size of the Xing header MPEG-1, bit rate in kbps. + */ + var XING_BITRATE1 = 128; + /** + * The size of the Xing header MPEG-2, bit rate in kbps. + */ + var XING_BITRATE2 = 64; + /** + * The size of the Xing header MPEG-2.5, bit rate in kbps. + */ + var XING_BITRATE25 = 32; + + /** + * ISO-8859-1 charset for byte to string operations. + */ + var ISO_8859_1 = null; //Charset.forName("ISO-8859-1"); + + /** + * VBR header magic string. + */ + var VBRTag0 = "Xing"; + /** + * VBR header magic string (VBR == VBRMode.vbr_off). + */ + var VBRTag1 = "Info"; + + /** + * Lookup table for fast CRC-16 computation. Uses the polynomial + * x^16+x^15+x^2+1 + */ + var crc16Lookup = [0x0000, 0xC0C1, 0xC181, 0x0140, + 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, + 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, + 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, + 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, + 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, + 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, + 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, + 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, + 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, + 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, + 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, + 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, + 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, + 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, + 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, + 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, + 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, + 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, + 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, + 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, + 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, + 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, + 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, + 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, + 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, + 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41, + 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, + 0x9901, 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, + 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, + 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, + 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, + 0x4100, 0x81C1, 0x8081, 0x4040]; + + /*********************************************************************** + * Robert Hegemann 2001-01-17 + ***********************************************************************/ + + function addVbr(v, bitrate) { + v.nVbrNumFrames++; + v.sum += bitrate; + v.seen++; + + if (v.seen < v.want) { + return; + } + + if (v.pos < v.size) { + v.bag[v.pos] = v.sum; + v.pos++; + v.seen = 0; + } + if (v.pos == v.size) { + for (var i = 1; i < v.size; i += 2) { + v.bag[i / 2] = v.bag[i]; + } + v.want *= 2; + v.pos /= 2; + } + } + + function xingSeekTable(v, t) { + if (v.pos <= 0) + return; + + for (var i = 1; i < NUMTOCENTRIES; ++i) { + var j = i / NUMTOCENTRIES, act, sum; + var indx = 0 | (Math.floor(j * v.pos)); + if (indx > v.pos - 1) + indx = v.pos - 1; + act = v.bag[indx]; + sum = v.sum; + var seek_point = 0 | (256. * act / sum); + if (seek_point > 255) + seek_point = 255; + t[i] = 0xff & seek_point; + } + } + + /** + * Add VBR entry, used to fill the VBR TOC entries. + * + * @param gfp + * global flags + */ + this.addVbrFrame = function (gfp) { + var gfc = gfp.internal_flags; + var kbps = Tables.bitrate_table[gfp.version][gfc.bitrate_index]; + addVbr(gfc.VBR_seek_table, kbps); + } + + /** + * Read big endian integer (4-bytes) from header. + * + * @param buf + * header containing the integer + * @param bufPos + * offset into the header + * @return extracted integer + */ + function extractInteger(buf, bufPos) { + var x = buf[bufPos + 0] & 0xff; + x <<= 8; + x |= buf[bufPos + 1] & 0xff; + x <<= 8; + x |= buf[bufPos + 2] & 0xff; + x <<= 8; + x |= buf[bufPos + 3] & 0xff; + return x; + } + + /** + * Write big endian integer (4-bytes) in the header. + * + * @param buf + * header to write the integer into + * @param bufPos + * offset into the header + * @param value + * integer value to write + */ + function createInteger(buf, bufPos, value) { + buf[bufPos + 0] = 0xff & ((value >> 24) & 0xff); + buf[bufPos + 1] = 0xff & ((value >> 16) & 0xff); + buf[bufPos + 2] = 0xff & ((value >> 8) & 0xff); + buf[bufPos + 3] = 0xff & (value & 0xff); + } + + /** + * Write big endian short (2-bytes) in the header. + * + * @param buf + * header to write the integer into + * @param bufPos + * offset into the header + * @param value + * integer value to write + */ + function createShort(buf, bufPos, value) { + buf[bufPos + 0] = 0xff & ((value >> 8) & 0xff); + buf[bufPos + 1] = 0xff & (value & 0xff); + } + + /** + * Check for magic strings (Xing/Info). + * + * @param buf + * header to check + * @param bufPos + * header offset to check + * @return magic string found + */ + function isVbrTag(buf, bufPos) { + return new String(buf, bufPos, VBRTag0.length(), ISO_8859_1) + .equals(VBRTag0) + || new String(buf, bufPos, VBRTag1.length(), ISO_8859_1) + .equals(VBRTag1); + } + + function shiftInBitsValue(x, n, v) { + return 0xff & ((x << n) | (v & ~(-1 << n))); + } + + /** + * Construct the MP3 header using the settings of the global flags. + * + * + * + * @param gfp + * global flags + * @param buffer + * header + */ + function setLameTagFrameHeader(gfp, buffer) { + var gfc = gfp.internal_flags; + + // MP3 Sync Word + buffer[0] = shiftInBitsValue(buffer[0], 8, 0xff); + + buffer[1] = shiftInBitsValue(buffer[1], 3, 7); + buffer[1] = shiftInBitsValue(buffer[1], 1, + (gfp.out_samplerate < 16000) ? 0 : 1); + // Version + buffer[1] = shiftInBitsValue(buffer[1], 1, gfp.version); + // 01 == Layer 3 + buffer[1] = shiftInBitsValue(buffer[1], 2, 4 - 3); + // Error protection + buffer[1] = shiftInBitsValue(buffer[1], 1, (!gfp.error_protection) ? 1 + : 0); + + // Bit rate + buffer[2] = shiftInBitsValue(buffer[2], 4, gfc.bitrate_index); + // Frequency + buffer[2] = shiftInBitsValue(buffer[2], 2, gfc.samplerate_index); + // Pad. Bit + buffer[2] = shiftInBitsValue(buffer[2], 1, 0); + // Priv. Bit + buffer[2] = shiftInBitsValue(buffer[2], 1, gfp.extension); + + // Mode + buffer[3] = shiftInBitsValue(buffer[3], 2, gfp.mode.ordinal()); + // Mode extension (Used with Joint Stereo) + buffer[3] = shiftInBitsValue(buffer[3], 2, gfc.mode_ext); + // Copy + buffer[3] = shiftInBitsValue(buffer[3], 1, gfp.copyright); + // Original + buffer[3] = shiftInBitsValue(buffer[3], 1, gfp.original); + // Emphasis + buffer[3] = shiftInBitsValue(buffer[3], 2, gfp.emphasis); + + /* the default VBR header. 48 kbps layer III, no padding, no crc */ + /* but sampling freq, mode and copyright/copy protection taken */ + /* from first valid frame */ + buffer[0] = 0xff; + var abyte = 0xff & (buffer[1] & 0xf1); + var bitrate; + if (1 == gfp.version) { + bitrate = XING_BITRATE1; + } else { + if (gfp.out_samplerate < 16000) + bitrate = XING_BITRATE25; + else + bitrate = XING_BITRATE2; + } + + if (gfp.VBR == VbrMode.vbr_off) + bitrate = gfp.brate; + + var bbyte; + if (gfp.free_format) + bbyte = 0x00; + else + bbyte = 0xff & (16 * lame.BitrateIndex(bitrate, gfp.version, + gfp.out_samplerate)); + + /* + * Use as much of the info from the real frames in the Xing header: + * samplerate, channels, crc, etc... + */ + if (gfp.version == 1) { + /* MPEG1 */ + buffer[1] = 0xff & (abyte | 0x0a); + /* was 0x0b; */ + abyte = 0xff & (buffer[2] & 0x0d); + /* AF keep also private bit */ + buffer[2] = 0xff & (bbyte | abyte); + /* 64kbs MPEG1 frame */ + } else { + /* MPEG2 */ + buffer[1] = 0xff & (abyte | 0x02); + /* was 0x03; */ + abyte = 0xff & (buffer[2] & 0x0d); + /* AF keep also private bit */ + buffer[2] = 0xff & (bbyte | abyte); + /* 64kbs MPEG2 frame */ + } + } + + /** + * Get VBR tag information + * + * @param buf + * header to analyze + * @param bufPos + * offset into the header + * @return VBR tag data + */ + this.getVbrTag = function (buf) { + var pTagData = new VBRTagData(); + var bufPos = 0; + + /* get Vbr header data */ + pTagData.flags = 0; + + /* get selected MPEG header data */ + var hId = (buf[bufPos + 1] >> 3) & 1; + var hSrIndex = (buf[bufPos + 2] >> 2) & 3; + var hMode = (buf[bufPos + 3] >> 6) & 3; + var hBitrate = ((buf[bufPos + 2] >> 4) & 0xf); + hBitrate = Tables.bitrate_table[hId][hBitrate]; + + /* check for FFE syncword */ + if ((buf[bufPos + 1] >> 4) == 0xE) + pTagData.samprate = Tables.samplerate_table[2][hSrIndex]; + else + pTagData.samprate = Tables.samplerate_table[hId][hSrIndex]; + + /* determine offset of header */ + if (hId != 0) { + /* mpeg1 */ + if (hMode != 3) + bufPos += (32 + 4); + else + bufPos += (17 + 4); + } else { + /* mpeg2 */ + if (hMode != 3) + bufPos += (17 + 4); + else + bufPos += (9 + 4); + } + + if (!isVbrTag(buf, bufPos)) + return null; + + bufPos += 4; + + pTagData.hId = hId; + + /* get flags */ + var head_flags = pTagData.flags = extractInteger(buf, bufPos); + bufPos += 4; + + if ((head_flags & FRAMES_FLAG) != 0) { + pTagData.frames = extractInteger(buf, bufPos); + bufPos += 4; + } + + if ((head_flags & BYTES_FLAG) != 0) { + pTagData.bytes = extractInteger(buf, bufPos); + bufPos += 4; + } + + if ((head_flags & TOC_FLAG) != 0) { + if (pTagData.toc != null) { + for (var i = 0; i < NUMTOCENTRIES; i++) + pTagData.toc[i] = buf[bufPos + i]; + } + bufPos += NUMTOCENTRIES; + } + + pTagData.vbrScale = -1; + + if ((head_flags & VBR_SCALE_FLAG) != 0) { + pTagData.vbrScale = extractInteger(buf, bufPos); + bufPos += 4; + } + + pTagData.headersize = ((hId + 1) * 72000 * hBitrate) + / pTagData.samprate; + + bufPos += 21; + var encDelay = buf[bufPos + 0] << 4; + encDelay += buf[bufPos + 1] >> 4; + var encPadding = (buf[bufPos + 1] & 0x0F) << 8; + encPadding += buf[bufPos + 2] & 0xff; + /* check for reasonable values (this may be an old Xing header, */ + /* not a INFO tag) */ + if (encDelay < 0 || encDelay > 3000) + encDelay = -1; + if (encPadding < 0 || encPadding > 3000) + encPadding = -1; + + pTagData.encDelay = encDelay; + pTagData.encPadding = encPadding; + + /* success */ + return pTagData; + } + + /** + * Initializes the header + * + * @param gfp + * global flags + */ + this.InitVbrTag = function (gfp) { + var gfc = gfp.internal_flags; + + /** + *
+         * Xing VBR pretends to be a 48kbs layer III frame.  (at 44.1kHz).
+         * (at 48kHz they use 56kbs since 48kbs frame not big enough for
+         * table of contents)
+         * let's always embed Xing header inside a 64kbs layer III frame.
+         * this gives us enough room for a LAME version string too.
+         * size determined by sampling frequency (MPEG1)
+         * 32kHz:    216 bytes@48kbs    288bytes@ 64kbs
+         * 44.1kHz:  156 bytes          208bytes@64kbs     (+1 if padding = 1)
+         * 48kHz:    144 bytes          192
+         *
+         * MPEG 2 values are the same since the framesize and samplerate
+         * are each reduced by a factor of 2.
+         * 
+ */ + var kbps_header; + if (1 == gfp.version) { + kbps_header = XING_BITRATE1; + } else { + if (gfp.out_samplerate < 16000) + kbps_header = XING_BITRATE25; + else + kbps_header = XING_BITRATE2; + } + + if (gfp.VBR == VbrMode.vbr_off) + kbps_header = gfp.brate; + + // make sure LAME Header fits into Frame + var totalFrameSize = ((gfp.version + 1) * 72000 * kbps_header) + / gfp.out_samplerate; + var headerSize = (gfc.sideinfo_len + LAMEHEADERSIZE); + gfc.VBR_seek_table.TotalFrameSize = totalFrameSize; + if (totalFrameSize < headerSize || totalFrameSize > MAXFRAMESIZE) { + /* disable tag, it wont fit */ + gfp.bWriteVbrTag = false; + return; + } + + gfc.VBR_seek_table.nVbrNumFrames = 0; + gfc.VBR_seek_table.nBytesWritten = 0; + gfc.VBR_seek_table.sum = 0; + + gfc.VBR_seek_table.seen = 0; + gfc.VBR_seek_table.want = 1; + gfc.VBR_seek_table.pos = 0; + + if (gfc.VBR_seek_table.bag == null) { + gfc.VBR_seek_table.bag = new int[400]; + gfc.VBR_seek_table.size = 400; + } + + // write dummy VBR tag of all 0's into bitstream + var buffer = new_byte(MAXFRAMESIZE); + + setLameTagFrameHeader(gfp, buffer); + var n = gfc.VBR_seek_table.TotalFrameSize; + for (var i = 0; i < n; ++i) { + bs.add_dummy_byte(gfp, buffer[i] & 0xff, 1); + } + } + + /** + * Fast CRC-16 computation (uses table crc16Lookup). + * + * @param value + * @param crc + * @return + */ + function crcUpdateLookup(value, crc) { + var tmp = crc ^ value; + crc = (crc >> 8) ^ crc16Lookup[tmp & 0xff]; + return crc; + } + + this.updateMusicCRC = function (crc, buffer, bufferPos, size) { + for (var i = 0; i < size; ++i) + crc[0] = crcUpdateLookup(buffer[bufferPos + i], crc[0]); + } + + /** + * Write LAME info: mini version + info on various switches used (Jonathan + * Dee 2001/08/31). + * + * @param gfp + * global flags + * @param musicLength + * music length + * @param streamBuffer + * pointer to output buffer + * @param streamBufferPos + * offset into the output buffer + * @param crc + * computation of CRC-16 of Lame Tag so far (starting at frame + * sync) + * @return number of bytes written to the stream + */ + function putLameVBR(gfp, musicLength, streamBuffer, streamBufferPos, crc) { + var gfc = gfp.internal_flags; + var bytesWritten = 0; + + /* encoder delay */ + var encDelay = gfp.encoder_delay; + /* encoder padding */ + var encPadding = gfp.encoder_padding; + + /* recall: gfp.VBR_q is for example set by the switch -V */ + /* gfp.quality by -q, -h, -f, etc */ + var quality = (100 - 10 * gfp.VBR_q - gfp.quality); + + var version = v.getLameVeryShortVersion(); + var vbr; + var revision = 0x00; + var revMethod; + // numbering different in vbr_mode vs. Lame tag + var vbrTypeTranslator = [1, 5, 3, 2, 4, 0, 3]; + var lowpass = 0 | (((gfp.lowpassfreq / 100.0) + .5) > 255 ? 255 + : (gfp.lowpassfreq / 100.0) + .5); + var peakSignalAmplitude = 0; + var radioReplayGain = 0; + var audiophileReplayGain = 0; + var noiseShaping = gfp.internal_flags.noise_shaping; + var stereoMode = 0; + var nonOptimal = 0; + var sourceFreq = 0; + var misc = 0; + var musicCRC = 0; + + // psy model type: Gpsycho or NsPsytune + var expNPsyTune = (gfp.exp_nspsytune & 1) != 0; + var safeJoint = (gfp.exp_nspsytune & 2) != 0; + var noGapMore = false; + var noGapPrevious = false; + var noGapCount = gfp.internal_flags.nogap_total; + var noGapCurr = gfp.internal_flags.nogap_current; + + // 4 bits + var athType = gfp.ATHtype; + var flags = 0; + + // vbr modes + var abrBitrate; + switch (gfp.VBR) { + case vbr_abr: + abrBitrate = gfp.VBR_mean_bitrate_kbps; + break; + case vbr_off: + abrBitrate = gfp.brate; + break; + default: + abrBitrate = gfp.VBR_min_bitrate_kbps; + } + + // revision and vbr method + if (gfp.VBR.ordinal() < vbrTypeTranslator.length) + vbr = vbrTypeTranslator[gfp.VBR.ordinal()]; + else + vbr = 0x00; // unknown + + revMethod = 0x10 * revision + vbr; + + // ReplayGain + if (gfc.findReplayGain) { + if (gfc.RadioGain > 0x1FE) + gfc.RadioGain = 0x1FE; + if (gfc.RadioGain < -0x1FE) + gfc.RadioGain = -0x1FE; + + // set name code + radioReplayGain = 0x2000; + // set originator code to `determined automatically' + radioReplayGain |= 0xC00; + + if (gfc.RadioGain >= 0) { + // set gain adjustment + radioReplayGain |= gfc.RadioGain; + } else { + // set the sign bit + radioReplayGain |= 0x200; + // set gain adjustment + radioReplayGain |= -gfc.RadioGain; + } + } + + // peak sample + if (gfc.findPeakSample) + peakSignalAmplitude = Math + .abs(0 | ((( gfc.PeakSample) / 32767.0) * Math.pow(2, 23) + .5)); + + // nogap + if (noGapCount != -1) { + if (noGapCurr > 0) + noGapPrevious = true; + + if (noGapCurr < noGapCount - 1) + noGapMore = true; + } + + // flags + flags = athType + ((expNPsyTune ? 1 : 0) << 4) + + ((safeJoint ? 1 : 0) << 5) + ((noGapMore ? 1 : 0) << 6) + + ((noGapPrevious ? 1 : 0) << 7); + + if (quality < 0) + quality = 0; + + // stereo mode field (Intensity stereo is not implemented) + switch (gfp.mode) { + case MONO: + stereoMode = 0; + break; + case STEREO: + stereoMode = 1; + break; + case DUAL_CHANNEL: + stereoMode = 2; + break; + case JOINT_STEREO: + if (gfp.force_ms) + stereoMode = 4; + else + stereoMode = 3; + break; + case NOT_SET: + //$FALL-THROUGH$ + default: + stereoMode = 7; + break; + } + + if (gfp.in_samplerate <= 32000) + sourceFreq = 0x00; + else if (gfp.in_samplerate == 48000) + sourceFreq = 0x02; + else if (gfp.in_samplerate > 48000) + sourceFreq = 0x03; + else { + // default is 44100Hz + sourceFreq = 0x01; + } + + // Check if the user overrided the default LAME behavior with some + // nasty options + if (gfp.short_blocks == ShortBlock.short_block_forced + || gfp.short_blocks == ShortBlock.short_block_dispensed + || ((gfp.lowpassfreq == -1) && (gfp.highpassfreq == -1)) || /* "-k" */ + (gfp.scale_left < gfp.scale_right) + || (gfp.scale_left > gfp.scale_right) + || (gfp.disable_reservoir && gfp.brate < 320) || gfp.noATH + || gfp.ATHonly || (athType == 0) || gfp.in_samplerate <= 32000) + nonOptimal = 1; + + misc = noiseShaping + (stereoMode << 2) + (nonOptimal << 5) + + (sourceFreq << 6); + + musicCRC = gfc.nMusicCRC; + + // Write all this information into the stream + + createInteger(streamBuffer, streamBufferPos + bytesWritten, quality); + bytesWritten += 4; + + for (var j = 0; j < 9; j++) { + streamBuffer[streamBufferPos + bytesWritten + j] = 0xff & version .charAt(j); + } + bytesWritten += 9; + + streamBuffer[streamBufferPos + bytesWritten] = 0xff & revMethod; + bytesWritten++; + + streamBuffer[streamBufferPos + bytesWritten] = 0xff & lowpass; + bytesWritten++; + + createInteger(streamBuffer, streamBufferPos + bytesWritten, + peakSignalAmplitude); + bytesWritten += 4; + + createShort(streamBuffer, streamBufferPos + bytesWritten, + radioReplayGain); + bytesWritten += 2; + + createShort(streamBuffer, streamBufferPos + bytesWritten, + audiophileReplayGain); + bytesWritten += 2; + + streamBuffer[streamBufferPos + bytesWritten] = 0xff & flags; + bytesWritten++; + + if (abrBitrate >= 255) + streamBuffer[streamBufferPos + bytesWritten] = 0xFF; + else + streamBuffer[streamBufferPos + bytesWritten] = 0xff & abrBitrate; + bytesWritten++; + + streamBuffer[streamBufferPos + bytesWritten] = 0xff & (encDelay >> 4); + streamBuffer[streamBufferPos + bytesWritten + 1] = 0xff & ((encDelay << 4) + (encPadding >> 8)); + streamBuffer[streamBufferPos + bytesWritten + 2] = 0xff & encPadding; + + bytesWritten += 3; + + streamBuffer[streamBufferPos + bytesWritten] = 0xff & misc; + bytesWritten++; + + // unused in rev0 + streamBuffer[streamBufferPos + bytesWritten++] = 0; + + createShort(streamBuffer, streamBufferPos + bytesWritten, gfp.preset); + bytesWritten += 2; + + createInteger(streamBuffer, streamBufferPos + bytesWritten, musicLength); + bytesWritten += 4; + + createShort(streamBuffer, streamBufferPos + bytesWritten, musicCRC); + bytesWritten += 2; + + // Calculate tag CRC.... must be done here, since it includes previous + // information + + for (var i = 0; i < bytesWritten; i++) + crc = crcUpdateLookup(streamBuffer[streamBufferPos + i], crc); + + createShort(streamBuffer, streamBufferPos + bytesWritten, crc); + bytesWritten += 2; + + return bytesWritten; + } + + function skipId3v2(fpStream) { + // seek to the beginning of the stream + fpStream.seek(0); + // read 10 bytes in case there's an ID3 version 2 header here + var id3v2Header = new_byte(10); + fpStream.readFully(id3v2Header); + /* does the stream begin with the ID3 version 2 file identifier? */ + var id3v2TagSize; + if (!new String(id3v2Header, "ISO-8859-1").startsWith("ID3")) { + /* + * the tag size (minus the 10-byte header) is encoded into four + * bytes where the most significant bit is clear in each byte + */ + id3v2TagSize = (((id3v2Header[6] & 0x7f) << 21) + | ((id3v2Header[7] & 0x7f) << 14) + | ((id3v2Header[8] & 0x7f) << 7) | (id3v2Header[9] & 0x7f)) + + id3v2Header.length; + } else { + /* no ID3 version 2 tag in this stream */ + id3v2TagSize = 0; + } + return id3v2TagSize; + } + + this.getLameTagFrame = function (gfp, buffer) { + var gfc = gfp.internal_flags; + + if (!gfp.bWriteVbrTag) { + return 0; + } + if (gfc.Class_ID != Lame.LAME_ID) { + return 0; + } + if (gfc.VBR_seek_table.pos <= 0) { + return 0; + } + if (buffer.length < gfc.VBR_seek_table.TotalFrameSize) { + return gfc.VBR_seek_table.TotalFrameSize; + } + + Arrays.fill(buffer, 0, gfc.VBR_seek_table.TotalFrameSize, 0); + + // 4 bytes frame header + setLameTagFrameHeader(gfp, buffer); + + // Create TOC entries + var toc = new_byte(NUMTOCENTRIES); + + if (gfp.free_format) { + for (var i = 1; i < NUMTOCENTRIES; ++i) + toc[i] = 0xff & (255 * i / 100); + } else { + xingSeekTable(gfc.VBR_seek_table, toc); + } + + // Start writing the tag after the zero frame + var streamIndex = gfc.sideinfo_len; + /** + * Note: Xing header specifies that Xing data goes in the ancillary data + * with NO ERROR PROTECTION. If error protecton in enabled, the Xing + * data still starts at the same offset, and now it is in sideinfo data + * block, and thus will not decode correctly by non-Xing tag aware + * players + */ + if (gfp.error_protection) + streamIndex -= 2; + + // Put Vbr tag + if (gfp.VBR == VbrMode.vbr_off) { + buffer[streamIndex++] = 0xff & VBRTag1.charAt(0); + buffer[streamIndex++] = 0xff & VBRTag1.charAt(1); + buffer[streamIndex++] = 0xff & VBRTag1.charAt(2); + buffer[streamIndex++] = 0xff & VBRTag1.charAt(3); + + } else { + buffer[streamIndex++] = 0xff & VBRTag0.charAt(0); + buffer[streamIndex++] = 0xff & VBRTag0.charAt(1); + buffer[streamIndex++] = 0xff & VBRTag0.charAt(2); + buffer[streamIndex++] = 0xff & VBRTag0.charAt(3); + } + + // Put header flags + createInteger(buffer, streamIndex, FRAMES_FLAG + BYTES_FLAG + TOC_FLAG + + VBR_SCALE_FLAG); + streamIndex += 4; + + // Put Total Number of frames + createInteger(buffer, streamIndex, gfc.VBR_seek_table.nVbrNumFrames); + streamIndex += 4; + + // Put total audio stream size, including Xing/LAME Header + var streamSize = (gfc.VBR_seek_table.nBytesWritten + gfc.VBR_seek_table.TotalFrameSize); + createInteger(buffer, streamIndex, 0 | streamSize); + streamIndex += 4; + + /* Put TOC */ + System.arraycopy(toc, 0, buffer, streamIndex, toc.length); + streamIndex += toc.length; + + if (gfp.error_protection) { + // (jo) error_protection: add crc16 information to header + bs.CRC_writeheader(gfc, buffer); + } + + // work out CRC so far: initially crc = 0 + var crc = 0x00; + for (var i = 0; i < streamIndex; i++) + crc = crcUpdateLookup(buffer[i], crc); + // Put LAME VBR info + streamIndex += putLameVBR(gfp, streamSize, buffer, streamIndex, crc); + + return gfc.VBR_seek_table.TotalFrameSize; + } + + /** + * Write final VBR tag to the file. + * + * @param gfp + * global flags + * @param stream + * stream to add the VBR tag to + * @return 0 (OK), -1 else + * @throws IOException + * I/O error + */ + this.putVbrTag = function (gfp, stream) { + var gfc = gfp.internal_flags; + + if (gfc.VBR_seek_table.pos <= 0) + return -1; + + // Seek to end of file + stream.seek(stream.length()); + + // Get file size, abort if file has zero length. + if (stream.length() == 0) + return -1; + + // The VBR tag may NOT be located at the beginning of the stream. If an + // ID3 version 2 tag was added, then it must be skipped to write the VBR + // tag data. + var id3v2TagSize = skipId3v2(stream); + + // Seek to the beginning of the stream + stream.seek(id3v2TagSize); + + var buffer = new_byte(MAXFRAMESIZE); + var bytes = getLameTagFrame(gfp, buffer); + if (bytes > buffer.length) { + return -1; + } + + if (bytes < 1) { + return 0; + } + + // Put it all to disk again + stream.write(buffer, 0, bytes); + // success + return 0; + } + +} + + + +BitStream.EQ = function (a, b) { + return (Math.abs(a) > Math.abs(b)) ? (Math.abs((a) - (b)) <= (Math + .abs(a) * 1e-6)) + : (Math.abs((a) - (b)) <= (Math.abs(b) * 1e-6)); +}; + +BitStream.NEQ = function (a, b) { + return !BitStream.EQ(a, b); +}; + +function BitStream() { + var self = this; + var CRC16_POLYNOMIAL = 0x8005; + + /* + * we work with ints, so when doing bit manipulation, we limit ourselves to + * MAX_LENGTH-2 just to be on the safe side + */ + var MAX_LENGTH = 32; + + //GainAnalysis ga; + //MPGLib mpg; + //Version ver; + //VBRTag vbr; + var ga = null; + var mpg = null; + var ver = null; + var vbr = null; + + //public final void setModules(GainAnalysis ga, MPGLib mpg, Version ver, + // VBRTag vbr) { + + this.setModules = function (_ga, _mpg, _ver, _vbr) { + ga = _ga; + mpg = _mpg; + ver = _ver; + vbr = _vbr; + }; + + /** + * Bit stream buffer. + */ + //private byte[] buf; + var buf = null; + /** + * Bit counter of bit stream. + */ + var totbit = 0; + /** + * Pointer to top byte in buffer. + */ + var bufByteIdx = 0; + /** + * Pointer to top bit of top byte in buffer. + */ + var bufBitIdx = 0; + + /** + * compute bitsperframe and mean_bits for a layer III frame + */ + this.getframebits = function (gfp) { + var gfc = gfp.internal_flags; + var bit_rate; + + /* get bitrate in kbps [?] */ + if (gfc.bitrate_index != 0) + bit_rate = Tables.bitrate_table[gfp.version][gfc.bitrate_index]; + else + bit_rate = gfp.brate; + + /* main encoding routine toggles padding on and off */ + /* one Layer3 Slot consists of 8 bits */ + var bytes = 0 | (gfp.version + 1) * 72000 * bit_rate / gfp.out_samplerate + gfc.padding; + return 8 * bytes; + }; + + function putheader_bits(gfc) { + System.arraycopy(gfc.header[gfc.w_ptr].buf, 0, buf, bufByteIdx, gfc.sideinfo_len); + bufByteIdx += gfc.sideinfo_len; + totbit += gfc.sideinfo_len * 8; + gfc.w_ptr = (gfc.w_ptr + 1) & (LameInternalFlags.MAX_HEADER_BUF - 1); + } + + /** + * write j bits into the bit stream + */ + function putbits2(gfc, val, j) { + + while (j > 0) { + var k; + if (bufBitIdx == 0) { + bufBitIdx = 8; + bufByteIdx++; + if (gfc.header[gfc.w_ptr].write_timing == totbit) { + putheader_bits(gfc); + } + buf[bufByteIdx] = 0; + } + + k = Math.min(j, bufBitIdx); + j -= k; + + bufBitIdx -= k; + + /* 32 too large on 32 bit machines */ + + buf[bufByteIdx] |= ((val >> j) << bufBitIdx); + totbit += k; + } + } + + /** + * write j bits into the bit stream, ignoring frame headers + */ + function putbits_noheaders(gfc, val, j) { + + while (j > 0) { + var k; + if (bufBitIdx == 0) { + bufBitIdx = 8; + bufByteIdx++; + buf[bufByteIdx] = 0; + } + + k = Math.min(j, bufBitIdx); + j -= k; + + bufBitIdx -= k; + + /* 32 too large on 32 bit machines */ + + buf[bufByteIdx] |= ((val >> j) << bufBitIdx); + totbit += k; + } + } + + /** + * Some combinations of bitrate, Fs, and stereo make it impossible to stuff + * out a frame using just main_data, due to the limited number of bits to + * indicate main_data_length. In these situations, we put stuffing bits into + * the ancillary data... + */ + function drain_into_ancillary(gfp, remainingBits) { + var gfc = gfp.internal_flags; + var i; + + if (remainingBits >= 8) { + putbits2(gfc, 0x4c, 8); + remainingBits -= 8; + } + if (remainingBits >= 8) { + putbits2(gfc, 0x41, 8); + remainingBits -= 8; + } + if (remainingBits >= 8) { + putbits2(gfc, 0x4d, 8); + remainingBits -= 8; + } + if (remainingBits >= 8) { + putbits2(gfc, 0x45, 8); + remainingBits -= 8; + } + + if (remainingBits >= 32) { + var version = ver.getLameShortVersion(); + if (remainingBits >= 32) + for (i = 0; i < version.length && remainingBits >= 8; ++i) { + remainingBits -= 8; + putbits2(gfc, version.charAt(i), 8); + } + } + + for (; remainingBits >= 1; remainingBits -= 1) { + putbits2(gfc, gfc.ancillary_flag, 1); + gfc.ancillary_flag ^= (!gfp.disable_reservoir ? 1 : 0); + } + + + } + + /** + * write N bits into the header + */ + function writeheader(gfc, val, j) { + var ptr = gfc.header[gfc.h_ptr].ptr; + + while (j > 0) { + var k = Math.min(j, 8 - (ptr & 7)); + j -= k; + /* >> 32 too large for 32 bit machines */ + + gfc.header[gfc.h_ptr].buf[ptr >> 3] |= ((val >> j)) << (8 - (ptr & 7) - k); + ptr += k; + } + gfc.header[gfc.h_ptr].ptr = ptr; + } + + function CRC_update(value, crc) { + value <<= 8; + for (var i = 0; i < 8; i++) { + value <<= 1; + crc <<= 1; + + if ((((crc ^ value) & 0x10000) != 0)) + crc ^= CRC16_POLYNOMIAL; + } + return crc; + } + + this.CRC_writeheader = function (gfc, header) { + var crc = 0xffff; + /* (jo) init crc16 for error_protection */ + + crc = CRC_update(header[2] & 0xff, crc); + crc = CRC_update(header[3] & 0xff, crc); + for (var i = 6; i < gfc.sideinfo_len; i++) { + crc = CRC_update(header[i] & 0xff, crc); + } + + header[4] = (byte)(crc >> 8); + header[5] = (byte)(crc & 255); + }; + + function encodeSideInfo2(gfp, bitsPerFrame) { + var gfc = gfp.internal_flags; + var l3_side; + var gr, ch; + + l3_side = gfc.l3_side; + gfc.header[gfc.h_ptr].ptr = 0; + Arrays.fill(gfc.header[gfc.h_ptr].buf, 0, gfc.sideinfo_len, 0); + if (gfp.out_samplerate < 16000) + writeheader(gfc, 0xffe, 12); + else + writeheader(gfc, 0xfff, 12); + writeheader(gfc, (gfp.version), 1); + writeheader(gfc, 4 - 3, 2); + writeheader(gfc, (!gfp.error_protection ? 1 : 0), 1); + writeheader(gfc, (gfc.bitrate_index), 4); + writeheader(gfc, (gfc.samplerate_index), 2); + writeheader(gfc, (gfc.padding), 1); + writeheader(gfc, (gfp.extension), 1); + writeheader(gfc, (gfp.mode.ordinal()), 2); + writeheader(gfc, (gfc.mode_ext), 2); + writeheader(gfc, (gfp.copyright), 1); + writeheader(gfc, (gfp.original), 1); + writeheader(gfc, (gfp.emphasis), 2); + if (gfp.error_protection) { + writeheader(gfc, 0, 16); + /* dummy */ + } + + if (gfp.version == 1) { + /* MPEG1 */ + writeheader(gfc, (l3_side.main_data_begin), 9); + + if (gfc.channels_out == 2) + writeheader(gfc, l3_side.private_bits, 3); + else + writeheader(gfc, l3_side.private_bits, 5); + + for (ch = 0; ch < gfc.channels_out; ch++) { + var band; + for (band = 0; band < 4; band++) { + writeheader(gfc, l3_side.scfsi[ch][band], 1); + } + } + + for (gr = 0; gr < 2; gr++) { + for (ch = 0; ch < gfc.channels_out; ch++) { + var gi = l3_side.tt[gr][ch]; + writeheader(gfc, gi.part2_3_length + gi.part2_length, 12); + writeheader(gfc, gi.big_values / 2, 9); + writeheader(gfc, gi.global_gain, 8); + writeheader(gfc, gi.scalefac_compress, 4); + + if (gi.block_type != Encoder.NORM_TYPE) { + writeheader(gfc, 1, 1); + /* window_switching_flag */ + writeheader(gfc, gi.block_type, 2); + writeheader(gfc, gi.mixed_block_flag, 1); + + if (gi.table_select[0] == 14) + gi.table_select[0] = 16; + writeheader(gfc, gi.table_select[0], 5); + if (gi.table_select[1] == 14) + gi.table_select[1] = 16; + writeheader(gfc, gi.table_select[1], 5); + + writeheader(gfc, gi.subblock_gain[0], 3); + writeheader(gfc, gi.subblock_gain[1], 3); + writeheader(gfc, gi.subblock_gain[2], 3); + } else { + writeheader(gfc, 0, 1); + /* window_switching_flag */ + if (gi.table_select[0] == 14) + gi.table_select[0] = 16; + writeheader(gfc, gi.table_select[0], 5); + if (gi.table_select[1] == 14) + gi.table_select[1] = 16; + writeheader(gfc, gi.table_select[1], 5); + if (gi.table_select[2] == 14) + gi.table_select[2] = 16; + writeheader(gfc, gi.table_select[2], 5); + + writeheader(gfc, gi.region0_count, 4); + writeheader(gfc, gi.region1_count, 3); + } + writeheader(gfc, gi.preflag, 1); + writeheader(gfc, gi.scalefac_scale, 1); + writeheader(gfc, gi.count1table_select, 1); + } + } + } else { + /* MPEG2 */ + writeheader(gfc, (l3_side.main_data_begin), 8); + writeheader(gfc, l3_side.private_bits, gfc.channels_out); + + gr = 0; + for (ch = 0; ch < gfc.channels_out; ch++) { + var gi = l3_side.tt[gr][ch]; + writeheader(gfc, gi.part2_3_length + gi.part2_length, 12); + writeheader(gfc, gi.big_values / 2, 9); + writeheader(gfc, gi.global_gain, 8); + writeheader(gfc, gi.scalefac_compress, 9); + + if (gi.block_type != Encoder.NORM_TYPE) { + writeheader(gfc, 1, 1); + /* window_switching_flag */ + writeheader(gfc, gi.block_type, 2); + writeheader(gfc, gi.mixed_block_flag, 1); + + if (gi.table_select[0] == 14) + gi.table_select[0] = 16; + writeheader(gfc, gi.table_select[0], 5); + if (gi.table_select[1] == 14) + gi.table_select[1] = 16; + writeheader(gfc, gi.table_select[1], 5); + + writeheader(gfc, gi.subblock_gain[0], 3); + writeheader(gfc, gi.subblock_gain[1], 3); + writeheader(gfc, gi.subblock_gain[2], 3); + } else { + writeheader(gfc, 0, 1); + /* window_switching_flag */ + if (gi.table_select[0] == 14) + gi.table_select[0] = 16; + writeheader(gfc, gi.table_select[0], 5); + if (gi.table_select[1] == 14) + gi.table_select[1] = 16; + writeheader(gfc, gi.table_select[1], 5); + if (gi.table_select[2] == 14) + gi.table_select[2] = 16; + writeheader(gfc, gi.table_select[2], 5); + + writeheader(gfc, gi.region0_count, 4); + writeheader(gfc, gi.region1_count, 3); + } + + writeheader(gfc, gi.scalefac_scale, 1); + writeheader(gfc, gi.count1table_select, 1); + } + } + + if (gfp.error_protection) { + /* (jo) error_protection: add crc16 information to header */ + CRC_writeheader(gfc, gfc.header[gfc.h_ptr].buf); + } + + { + var old = gfc.h_ptr; + + gfc.h_ptr = (old + 1) & (LameInternalFlags.MAX_HEADER_BUF - 1); + gfc.header[gfc.h_ptr].write_timing = gfc.header[old].write_timing + + bitsPerFrame; + + if (gfc.h_ptr == gfc.w_ptr) { + /* yikes! we are out of header buffer space */ + System.err + .println("Error: MAX_HEADER_BUF too small in bitstream.c \n"); + } + + } + } + + function huffman_coder_count1(gfc, gi) { + /* Write count1 area */ + var h = Tables.ht[gi.count1table_select + 32]; + var i, bits = 0; + + var ix = gi.big_values; + var xr = gi.big_values; + + for (i = (gi.count1 - gi.big_values) / 4; i > 0; --i) { + var huffbits = 0; + var p = 0, v; + + v = gi.l3_enc[ix + 0]; + if (v != 0) { + p += 8; + if (gi.xr[xr + 0] < 0) + huffbits++; + } + + v = gi.l3_enc[ix + 1]; + if (v != 0) { + p += 4; + huffbits *= 2; + if (gi.xr[xr + 1] < 0) + huffbits++; + } + + v = gi.l3_enc[ix + 2]; + if (v != 0) { + p += 2; + huffbits *= 2; + if (gi.xr[xr + 2] < 0) + huffbits++; + } + + v = gi.l3_enc[ix + 3]; + if (v != 0) { + p++; + huffbits *= 2; + if (gi.xr[xr + 3] < 0) + huffbits++; + } + + ix += 4; + xr += 4; + putbits2(gfc, huffbits + h.table[p], h.hlen[p]); + bits += h.hlen[p]; + } + return bits; + } + + /** + * Implements the pseudocode of page 98 of the IS + */ + function Huffmancode(gfc, tableindex, start, end, gi) { + var h = Tables.ht[tableindex]; + var bits = 0; + + if (0 == tableindex) + return bits; + + for (var i = start; i < end; i += 2) { + var cbits = 0; + var xbits = 0; + var linbits = h.xlen; + var xlen = h.xlen; + var ext = 0; + var x1 = gi.l3_enc[i]; + var x2 = gi.l3_enc[i + 1]; + + if (x1 != 0) { + if (gi.xr[i] < 0) + ext++; + cbits--; + } + + if (tableindex > 15) { + /* use ESC-words */ + if (x1 > 14) { + var linbits_x1 = x1 - 15; + ext |= linbits_x1 << 1; + xbits = linbits; + x1 = 15; + } + + if (x2 > 14) { + var linbits_x2 = x2 - 15; + ext <<= linbits; + ext |= linbits_x2; + xbits += linbits; + x2 = 15; + } + xlen = 16; + } + + if (x2 != 0) { + ext <<= 1; + if (gi.xr[i + 1] < 0) + ext++; + cbits--; + } + + + x1 = x1 * xlen + x2; + xbits -= cbits; + cbits += h.hlen[x1]; + + + putbits2(gfc, h.table[x1], cbits); + putbits2(gfc, ext, xbits); + bits += cbits + xbits; + } + return bits; + } + + /** + * Note the discussion of huffmancodebits() on pages 28 and 29 of the IS, as + * well as the definitions of the side information on pages 26 and 27. + */ + function ShortHuffmancodebits(gfc, gi) { + var region1Start = 3 * gfc.scalefac_band.s[3]; + if (region1Start > gi.big_values) + region1Start = gi.big_values; + + /* short blocks do not have a region2 */ + var bits = Huffmancode(gfc, gi.table_select[0], 0, region1Start, gi); + bits += Huffmancode(gfc, gi.table_select[1], region1Start, + gi.big_values, gi); + return bits; + } + + function LongHuffmancodebits(gfc, gi) { + var bigvalues, bits; + var region1Start, region2Start; + + bigvalues = gi.big_values; + + var i = gi.region0_count + 1; + region1Start = gfc.scalefac_band.l[i]; + i += gi.region1_count + 1; + region2Start = gfc.scalefac_band.l[i]; + + if (region1Start > bigvalues) + region1Start = bigvalues; + + if (region2Start > bigvalues) + region2Start = bigvalues; + + bits = Huffmancode(gfc, gi.table_select[0], 0, region1Start, gi); + bits += Huffmancode(gfc, gi.table_select[1], region1Start, + region2Start, gi); + bits += Huffmancode(gfc, gi.table_select[2], region2Start, bigvalues, + gi); + return bits; + } + + function writeMainData(gfp) { + var gr, ch, sfb, data_bits, tot_bits = 0; + var gfc = gfp.internal_flags; + var l3_side = gfc.l3_side; + + if (gfp.version == 1) { + /* MPEG 1 */ + for (gr = 0; gr < 2; gr++) { + for (ch = 0; ch < gfc.channels_out; ch++) { + var gi = l3_side.tt[gr][ch]; + var slen1 = Takehiro.slen1_tab[gi.scalefac_compress]; + var slen2 = Takehiro.slen2_tab[gi.scalefac_compress]; + data_bits = 0; + for (sfb = 0; sfb < gi.sfbdivide; sfb++) { + if (gi.scalefac[sfb] == -1) + continue; + /* scfsi is used */ + putbits2(gfc, gi.scalefac[sfb], slen1); + data_bits += slen1; + } + for (; sfb < gi.sfbmax; sfb++) { + if (gi.scalefac[sfb] == -1) + continue; + /* scfsi is used */ + putbits2(gfc, gi.scalefac[sfb], slen2); + data_bits += slen2; + } + + if (gi.block_type == Encoder.SHORT_TYPE) { + data_bits += ShortHuffmancodebits(gfc, gi); + } else { + data_bits += LongHuffmancodebits(gfc, gi); + } + data_bits += huffman_coder_count1(gfc, gi); + /* does bitcount in quantize.c agree with actual bit count? */ + tot_bits += data_bits; + } + /* for ch */ + } + /* for gr */ + } else { + /* MPEG 2 */ + gr = 0; + for (ch = 0; ch < gfc.channels_out; ch++) { + var gi = l3_side.tt[gr][ch]; + var i, sfb_partition, scale_bits = 0; + data_bits = 0; + sfb = 0; + sfb_partition = 0; + + if (gi.block_type == Encoder.SHORT_TYPE) { + for (; sfb_partition < 4; sfb_partition++) { + var sfbs = gi.sfb_partition_table[sfb_partition] / 3; + var slen = gi.slen[sfb_partition]; + for (i = 0; i < sfbs; i++, sfb++) { + putbits2(gfc, + Math.max(gi.scalefac[sfb * 3 + 0], 0), slen); + putbits2(gfc, + Math.max(gi.scalefac[sfb * 3 + 1], 0), slen); + putbits2(gfc, + Math.max(gi.scalefac[sfb * 3 + 2], 0), slen); + scale_bits += 3 * slen; + } + } + data_bits += ShortHuffmancodebits(gfc, gi); + } else { + for (; sfb_partition < 4; sfb_partition++) { + var sfbs = gi.sfb_partition_table[sfb_partition]; + var slen = gi.slen[sfb_partition]; + for (i = 0; i < sfbs; i++, sfb++) { + putbits2(gfc, Math.max(gi.scalefac[sfb], 0), slen); + scale_bits += slen; + } + } + data_bits += LongHuffmancodebits(gfc, gi); + } + data_bits += huffman_coder_count1(gfc, gi); + /* does bitcount in quantize.c agree with actual bit count? */ + tot_bits += scale_bits + data_bits; + } + /* for ch */ + } + /* for gf */ + return tot_bits; + } + + /* main_data */ + + function TotalBytes() { + this.total = 0; + } + + /* + * compute the number of bits required to flush all mp3 frames currently in + * the buffer. This should be the same as the reservoir size. Only call this + * routine between frames - i.e. only after all headers and data have been + * added to the buffer by format_bitstream(). + * + * Also compute total_bits_output = size of mp3 buffer (including frame + * headers which may not have yet been send to the mp3 buffer) + number of + * bits needed to flush all mp3 frames. + * + * total_bytes_output is the size of the mp3 output buffer if + * lame_encode_flush_nogap() was called right now. + */ + function compute_flushbits(gfp, total_bytes_output) { + var gfc = gfp.internal_flags; + var flushbits, remaining_headers; + var bitsPerFrame; + var last_ptr, first_ptr; + first_ptr = gfc.w_ptr; + /* first header to add to bitstream */ + last_ptr = gfc.h_ptr - 1; + /* last header to add to bitstream */ + if (last_ptr == -1) + last_ptr = LameInternalFlags.MAX_HEADER_BUF - 1; + + /* add this many bits to bitstream so we can flush all headers */ + flushbits = gfc.header[last_ptr].write_timing - totbit; + total_bytes_output.total = flushbits; + + if (flushbits >= 0) { + /* if flushbits >= 0, some headers have not yet been written */ + /* reduce flushbits by the size of the headers */ + remaining_headers = 1 + last_ptr - first_ptr; + if (last_ptr < first_ptr) + remaining_headers = 1 + last_ptr - first_ptr + + LameInternalFlags.MAX_HEADER_BUF; + flushbits -= remaining_headers * 8 * gfc.sideinfo_len; + } + + /* + * finally, add some bits so that the last frame is complete these bits + * are not necessary to decode the last frame, but some decoders will + * ignore last frame if these bits are missing + */ + bitsPerFrame = self.getframebits(gfp); + flushbits += bitsPerFrame; + total_bytes_output.total += bitsPerFrame; + /* round up: */ + if ((total_bytes_output.total % 8) != 0) + total_bytes_output.total = 1 + (total_bytes_output.total / 8); + else + total_bytes_output.total = (total_bytes_output.total / 8); + total_bytes_output.total += bufByteIdx + 1; + + if (flushbits < 0) { + System.err.println("strange error flushing buffer ... \n"); + } + return flushbits; + } + + this.flush_bitstream = function (gfp) { + var gfc = gfp.internal_flags; + var l3_side; + var flushbits; + var last_ptr = gfc.h_ptr - 1; + /* last header to add to bitstream */ + if (last_ptr == -1) + last_ptr = LameInternalFlags.MAX_HEADER_BUF - 1; + l3_side = gfc.l3_side; + + if ((flushbits = compute_flushbits(gfp, new TotalBytes())) < 0) + return; + drain_into_ancillary(gfp, flushbits); + + /* check that the 100% of the last frame has been written to bitstream */ + + /* + * we have padded out all frames with ancillary data, which is the same + * as filling the bitreservoir with ancillary data, so : + */ + gfc.ResvSize = 0; + l3_side.main_data_begin = 0; + + /* save the ReplayGain value */ + if (gfc.findReplayGain) { + var RadioGain = ga.GetTitleGain(gfc.rgdata); + gfc.RadioGain = Math.floor(RadioGain * 10.0 + 0.5) | 0; + /* round to nearest */ + } + + /* find the gain and scale change required for no clipping */ + if (gfc.findPeakSample) { + gfc.noclipGainChange = Math.ceil(Math + .log10(gfc.PeakSample / 32767.0) * 20.0 * 10.0) | 0; + /* round up */ + + if (gfc.noclipGainChange > 0) { + /* clipping occurs */ + if (EQ(gfp.scale, 1.0) || EQ(gfp.scale, 0.0)) + gfc.noclipScale = (Math + .floor((32767.0 / gfc.PeakSample) * 100.0) / 100.0); + /* round down */ + else { + /* + * the user specified his own scaling factor. We could + * suggest the scaling factor of + * (32767.0/gfp.PeakSample)*(gfp.scale) but it's usually + * very inaccurate. So we'd rather not advice him on the + * scaling factor. + */ + gfc.noclipScale = -1; + } + } else + /* no clipping */ + gfc.noclipScale = -1; + } + }; + + this.add_dummy_byte = function (gfp, val, n) { + var gfc = gfp.internal_flags; + var i; + + while (n-- > 0) { + putbits_noheaders(gfc, val, 8); + + for (i = 0; i < LameInternalFlags.MAX_HEADER_BUF; ++i) + gfc.header[i].write_timing += 8; + } + }; + + /** + * This is called after a frame of audio has been quantized and coded. It + * will write the encoded audio to the bitstream. Note that from a layer3 + * encoder's perspective the bit stream is primarily a series of main_data() + * blocks, with header and side information inserted at the proper locations + * to maintain framing. (See Figure A.7 in the IS). + */ + this.format_bitstream = function (gfp) { + var gfc = gfp.internal_flags; + var l3_side; + l3_side = gfc.l3_side; + + var bitsPerFrame = this.getframebits(gfp); + drain_into_ancillary(gfp, l3_side.resvDrain_pre); + + encodeSideInfo2(gfp, bitsPerFrame); + var bits = 8 * gfc.sideinfo_len; + bits += writeMainData(gfp); + drain_into_ancillary(gfp, l3_side.resvDrain_post); + bits += l3_side.resvDrain_post; + + l3_side.main_data_begin += (bitsPerFrame - bits) / 8; + + /* + * compare number of bits needed to clear all buffered mp3 frames with + * what we think the resvsize is: + */ + if (compute_flushbits(gfp, new TotalBytes()) != gfc.ResvSize) { + System.err.println("Internal buffer inconsistency. flushbits <> ResvSize"); + } + + /* + * compare main_data_begin for the next frame with what we think the + * resvsize is: + */ + if ((l3_side.main_data_begin * 8) != gfc.ResvSize) { + System.err.printf("bit reservoir error: \n" + + "l3_side.main_data_begin: %d \n" + + "Resvoir size: %d \n" + + "resv drain (post) %d \n" + + "resv drain (pre) %d \n" + + "header and sideinfo: %d \n" + + "data bits: %d \n" + + "total bits: %d (remainder: %d) \n" + + "bitsperframe: %d \n", + 8 * l3_side.main_data_begin, gfc.ResvSize, + l3_side.resvDrain_post, l3_side.resvDrain_pre, + 8 * gfc.sideinfo_len, bits - l3_side.resvDrain_post - 8 + * gfc.sideinfo_len, bits, bits % 8, bitsPerFrame); + + System.err.println("This is a fatal error. It has several possible causes:"); + System.err.println("90%% LAME compiled with buggy version of gcc using advanced optimizations"); + System.err.println(" 9%% Your system is overclocked"); + System.err.println(" 1%% bug in LAME encoding library"); + + gfc.ResvSize = l3_side.main_data_begin * 8; + } + //; + + if (totbit > 1000000000) { + /* + * to avoid totbit overflow, (at 8h encoding at 128kbs) lets reset + * bit counter + */ + var i; + for (i = 0; i < LameInternalFlags.MAX_HEADER_BUF; ++i) + gfc.header[i].write_timing -= totbit; + totbit = 0; + } + + return 0; + }; + + /** + *
+     * copy data out of the internal MP3 bit buffer into a user supplied
+     *       unsigned char buffer.
+     *
+     *       mp3data=0      indicates data in buffer is an id3tags and VBR tags
+     *       mp3data=1      data is real mp3 frame data.
+     * 
+ */ + this.copy_buffer = function (gfc, buffer, bufferPos, size, mp3data) { + var minimum = bufByteIdx + 1; + if (minimum <= 0) + return 0; + if (size != 0 && minimum > size) { + /* buffer is too small */ + return -1; + } + System.arraycopy(buf, 0, buffer, bufferPos, minimum); + bufByteIdx = -1; + bufBitIdx = 0; + + if (mp3data != 0) { + var crc = new_int(1); + crc[0] = gfc.nMusicCRC; + vbr.updateMusicCRC(crc, buffer, bufferPos, minimum); + gfc.nMusicCRC = crc[0]; + + /** + * sum number of bytes belonging to the mp3 stream this info will be + * written into the Xing/LAME header for seeking + */ + if (minimum > 0) { + gfc.VBR_seek_table.nBytesWritten += minimum; + } + + if (gfc.decode_on_the_fly) { /* decode the frame */ + var pcm_buf = new_float_n([2, 1152]); + var mp3_in = minimum; + var samples_out = -1; + var i; + + /* re-synthesis to pcm. Repeat until we get a samples_out=0 */ + while (samples_out != 0) { + + samples_out = mpg.hip_decode1_unclipped(gfc.hip, buffer, + bufferPos, mp3_in, pcm_buf[0], pcm_buf[1]); + /* + * samples_out = 0: need more data to decode samples_out = + * -1: error. Lets assume 0 pcm output samples_out = number + * of samples output + */ + + /* + * set the lenght of the mp3 input buffer to zero, so that + * in the next iteration of the loop we will be querying + * mpglib about buffered data + */ + mp3_in = 0; + + if (samples_out == -1) { + /* + * error decoding. Not fatal, but might screw up the + * ReplayGain tag. What should we do? Ignore for now + */ + samples_out = 0; + } + if (samples_out > 0) { + /* process the PCM data */ + + /* + * this should not be possible, and indicates we have + * overflown the pcm_buf buffer + */ + + if (gfc.findPeakSample) { + for (i = 0; i < samples_out; i++) { + if (pcm_buf[0][i] > gfc.PeakSample) + gfc.PeakSample = pcm_buf[0][i]; + else if (-pcm_buf[0][i] > gfc.PeakSample) + gfc.PeakSample = -pcm_buf[0][i]; + } + if (gfc.channels_out > 1) + for (i = 0; i < samples_out; i++) { + if (pcm_buf[1][i] > gfc.PeakSample) + gfc.PeakSample = pcm_buf[1][i]; + else if (-pcm_buf[1][i] > gfc.PeakSample) + gfc.PeakSample = -pcm_buf[1][i]; + } + } + + if (gfc.findReplayGain) + if (ga.AnalyzeSamples(gfc.rgdata, pcm_buf[0], 0, + pcm_buf[1], 0, samples_out, + gfc.channels_out) == GainAnalysis.GAIN_ANALYSIS_ERROR) + return -6; + + } + /* if (samples_out>0) */ + } + /* while (samples_out!=0) */ + } + /* if (gfc.decode_on_the_fly) */ + + } + /* if (mp3data) */ + return minimum; + }; + + this.init_bit_stream_w = function (gfc) { + buf = new_byte(Lame.LAME_MAXMP3BUFFER); + + gfc.h_ptr = gfc.w_ptr = 0; + gfc.header[gfc.h_ptr].write_timing = 0; + bufByteIdx = -1; + bufBitIdx = 0; + totbit = 0; + }; + + // From machine.h + + +} + +function HuffCodeTab(len, max, tab, hl) { + this.xlen = len; + this.linmax = max; + this.table = tab; + this.hlen = hl; +} + +var Tables = {}; + + +Tables.t1HB = [ + 1, 1, + 1, 0 +]; + +Tables.t2HB = [ + 1, 2, 1, + 3, 1, 1, + 3, 2, 0 +]; + +Tables.t3HB = [ + 3, 2, 1, + 1, 1, 1, + 3, 2, 0 +]; + +Tables.t5HB = [ + 1, 2, 6, 5, + 3, 1, 4, 4, + 7, 5, 7, 1, + 6, 1, 1, 0 +]; + +Tables.t6HB = [ + 7, 3, 5, 1, + 6, 2, 3, 2, + 5, 4, 4, 1, + 3, 3, 2, 0 +]; + +Tables.t7HB = [ + 1, 2, 10, 19, 16, 10, + 3, 3, 7, 10, 5, 3, + 11, 4, 13, 17, 8, 4, + 12, 11, 18, 15, 11, 2, + 7, 6, 9, 14, 3, 1, + 6, 4, 5, 3, 2, 0 +]; + +Tables.t8HB = [ + 3, 4, 6, 18, 12, 5, + 5, 1, 2, 16, 9, 3, + 7, 3, 5, 14, 7, 3, + 19, 17, 15, 13, 10, 4, + 13, 5, 8, 11, 5, 1, + 12, 4, 4, 1, 1, 0 +]; + +Tables.t9HB = [ + 7, 5, 9, 14, 15, 7, + 6, 4, 5, 5, 6, 7, + 7, 6, 8, 8, 8, 5, + 15, 6, 9, 10, 5, 1, + 11, 7, 9, 6, 4, 1, + 14, 4, 6, 2, 6, 0 +]; + +Tables.t10HB = [ + 1, 2, 10, 23, 35, 30, 12, 17, + 3, 3, 8, 12, 18, 21, 12, 7, + 11, 9, 15, 21, 32, 40, 19, 6, + 14, 13, 22, 34, 46, 23, 18, 7, + 20, 19, 33, 47, 27, 22, 9, 3, + 31, 22, 41, 26, 21, 20, 5, 3, + 14, 13, 10, 11, 16, 6, 5, 1, + 9, 8, 7, 8, 4, 4, 2, 0 +]; + +Tables.t11HB = [ + 3, 4, 10, 24, 34, 33, 21, 15, + 5, 3, 4, 10, 32, 17, 11, 10, + 11, 7, 13, 18, 30, 31, 20, 5, + 25, 11, 19, 59, 27, 18, 12, 5, + 35, 33, 31, 58, 30, 16, 7, 5, + 28, 26, 32, 19, 17, 15, 8, 14, + 14, 12, 9, 13, 14, 9, 4, 1, + 11, 4, 6, 6, 6, 3, 2, 0 +]; + +Tables.t12HB = [ + 9, 6, 16, 33, 41, 39, 38, 26, + 7, 5, 6, 9, 23, 16, 26, 11, + 17, 7, 11, 14, 21, 30, 10, 7, + 17, 10, 15, 12, 18, 28, 14, 5, + 32, 13, 22, 19, 18, 16, 9, 5, + 40, 17, 31, 29, 17, 13, 4, 2, + 27, 12, 11, 15, 10, 7, 4, 1, + 27, 12, 8, 12, 6, 3, 1, 0 +]; + +Tables.t13HB = [ + 1, 5, 14, 21, 34, 51, 46, 71, 42, 52, 68, 52, 67, 44, 43, 19, + 3, 4, 12, 19, 31, 26, 44, 33, 31, 24, 32, 24, 31, 35, 22, 14, + 15, 13, 23, 36, 59, 49, 77, 65, 29, 40, 30, 40, 27, 33, 42, 16, + 22, 20, 37, 61, 56, 79, 73, 64, 43, 76, 56, 37, 26, 31, 25, 14, + 35, 16, 60, 57, 97, 75, 114, 91, 54, 73, 55, 41, 48, 53, 23, 24, + 58, 27, 50, 96, 76, 70, 93, 84, 77, 58, 79, 29, 74, 49, 41, 17, + 47, 45, 78, 74, 115, 94, 90, 79, 69, 83, 71, 50, 59, 38, 36, 15, + 72, 34, 56, 95, 92, 85, 91, 90, 86, 73, 77, 65, 51, 44, 43, 42, + 43, 20, 30, 44, 55, 78, 72, 87, 78, 61, 46, 54, 37, 30, 20, 16, + 53, 25, 41, 37, 44, 59, 54, 81, 66, 76, 57, 54, 37, 18, 39, 11, + 35, 33, 31, 57, 42, 82, 72, 80, 47, 58, 55, 21, 22, 26, 38, 22, + 53, 25, 23, 38, 70, 60, 51, 36, 55, 26, 34, 23, 27, 14, 9, 7, + 34, 32, 28, 39, 49, 75, 30, 52, 48, 40, 52, 28, 18, 17, 9, 5, + 45, 21, 34, 64, 56, 50, 49, 45, 31, 19, 12, 15, 10, 7, 6, 3, + 48, 23, 20, 39, 36, 35, 53, 21, 16, 23, 13, 10, 6, 1, 4, 2, + 16, 15, 17, 27, 25, 20, 29, 11, 17, 12, 16, 8, 1, 1, 0, 1 +]; + +Tables.t15HB = [ + 7, 12, 18, 53, 47, 76, 124, 108, 89, 123, 108, 119, 107, 81, 122, 63, + 13, 5, 16, 27, 46, 36, 61, 51, 42, 70, 52, 83, 65, 41, 59, 36, + 19, 17, 15, 24, 41, 34, 59, 48, 40, 64, 50, 78, 62, 80, 56, 33, + 29, 28, 25, 43, 39, 63, 55, 93, 76, 59, 93, 72, 54, 75, 50, 29, + 52, 22, 42, 40, 67, 57, 95, 79, 72, 57, 89, 69, 49, 66, 46, 27, + 77, 37, 35, 66, 58, 52, 91, 74, 62, 48, 79, 63, 90, 62, 40, 38, + 125, 32, 60, 56, 50, 92, 78, 65, 55, 87, 71, 51, 73, 51, 70, 30, + 109, 53, 49, 94, 88, 75, 66, 122, 91, 73, 56, 42, 64, 44, 21, 25, + 90, 43, 41, 77, 73, 63, 56, 92, 77, 66, 47, 67, 48, 53, 36, 20, + 71, 34, 67, 60, 58, 49, 88, 76, 67, 106, 71, 54, 38, 39, 23, 15, + 109, 53, 51, 47, 90, 82, 58, 57, 48, 72, 57, 41, 23, 27, 62, 9, + 86, 42, 40, 37, 70, 64, 52, 43, 70, 55, 42, 25, 29, 18, 11, 11, + 118, 68, 30, 55, 50, 46, 74, 65, 49, 39, 24, 16, 22, 13, 14, 7, + 91, 44, 39, 38, 34, 63, 52, 45, 31, 52, 28, 19, 14, 8, 9, 3, + 123, 60, 58, 53, 47, 43, 32, 22, 37, 24, 17, 12, 15, 10, 2, 1, + 71, 37, 34, 30, 28, 20, 17, 26, 21, 16, 10, 6, 8, 6, 2, 0 +]; + +Tables.t16HB = [ + 1, 5, 14, 44, 74, 63, 110, 93, 172, 149, 138, 242, 225, 195, 376, 17, + 3, 4, 12, 20, 35, 62, 53, 47, 83, 75, 68, 119, 201, 107, 207, 9, + 15, 13, 23, 38, 67, 58, 103, 90, 161, 72, 127, 117, 110, 209, 206, 16, + 45, 21, 39, 69, 64, 114, 99, 87, 158, 140, 252, 212, 199, 387, 365, 26, + 75, 36, 68, 65, 115, 101, 179, 164, 155, 264, 246, 226, 395, 382, 362, 9, + 66, 30, 59, 56, 102, 185, 173, 265, 142, 253, 232, 400, 388, 378, 445, 16, + 111, 54, 52, 100, 184, 178, 160, 133, 257, 244, 228, 217, 385, 366, 715, 10, + 98, 48, 91, 88, 165, 157, 148, 261, 248, 407, 397, 372, 380, 889, 884, 8, + 85, 84, 81, 159, 156, 143, 260, 249, 427, 401, 392, 383, 727, 713, 708, 7, + 154, 76, 73, 141, 131, 256, 245, 426, 406, 394, 384, 735, 359, 710, 352, 11, + 139, 129, 67, 125, 247, 233, 229, 219, 393, 743, 737, 720, 885, 882, 439, 4, + 243, 120, 118, 115, 227, 223, 396, 746, 742, 736, 721, 712, 706, 223, 436, 6, + 202, 224, 222, 218, 216, 389, 386, 381, 364, 888, 443, 707, 440, 437, 1728, 4, + 747, 211, 210, 208, 370, 379, 734, 723, 714, 1735, 883, 877, 876, 3459, 865, 2, + 377, 369, 102, 187, 726, 722, 358, 711, 709, 866, 1734, 871, 3458, 870, 434, 0, + 12, 10, 7, 11, 10, 17, 11, 9, 13, 12, 10, 7, 5, 3, 1, 3 +]; + +Tables.t24HB = [ + 15, 13, 46, 80, 146, 262, 248, 434, 426, 669, 653, 649, 621, 517, 1032, 88, + 14, 12, 21, 38, 71, 130, 122, 216, 209, 198, 327, 345, 319, 297, 279, 42, + 47, 22, 41, 74, 68, 128, 120, 221, 207, 194, 182, 340, 315, 295, 541, 18, + 81, 39, 75, 70, 134, 125, 116, 220, 204, 190, 178, 325, 311, 293, 271, 16, + 147, 72, 69, 135, 127, 118, 112, 210, 200, 188, 352, 323, 306, 285, 540, 14, + 263, 66, 129, 126, 119, 114, 214, 202, 192, 180, 341, 317, 301, 281, 262, 12, + 249, 123, 121, 117, 113, 215, 206, 195, 185, 347, 330, 308, 291, 272, 520, 10, + 435, 115, 111, 109, 211, 203, 196, 187, 353, 332, 313, 298, 283, 531, 381, 17, + 427, 212, 208, 205, 201, 193, 186, 177, 169, 320, 303, 286, 268, 514, 377, 16, + 335, 199, 197, 191, 189, 181, 174, 333, 321, 305, 289, 275, 521, 379, 371, 11, + 668, 184, 183, 179, 175, 344, 331, 314, 304, 290, 277, 530, 383, 373, 366, 10, + 652, 346, 171, 168, 164, 318, 309, 299, 287, 276, 263, 513, 375, 368, 362, 6, + 648, 322, 316, 312, 307, 302, 292, 284, 269, 261, 512, 376, 370, 364, 359, 4, + 620, 300, 296, 294, 288, 282, 273, 266, 515, 380, 374, 369, 365, 361, 357, 2, + 1033, 280, 278, 274, 267, 264, 259, 382, 378, 372, 367, 363, 360, 358, 356, 0, + 43, 20, 19, 17, 15, 13, 11, 9, 7, 6, 4, 7, 5, 3, 1, 3 +]; + +Tables.t32HB = [ + 1 << 0, 5 << 1, 4 << 1, 5 << 2, 6 << 1, 5 << 2, 4 << 2, 4 << 3, + 7 << 1, 3 << 2, 6 << 2, 0 << 3, 7 << 2, 2 << 3, 3 << 3, 1 << 4 +]; + +Tables.t33HB = [ + 15 << 0, 14 << 1, 13 << 1, 12 << 2, 11 << 1, 10 << 2, 9 << 2, 8 << 3, + 7 << 1, 6 << 2, 5 << 2, 4 << 3, 3 << 2, 2 << 3, 1 << 3, 0 << 4 +]; + +Tables.t1l = [ + 1, 4, + 3, 5 +]; + +Tables.t2l = [ + 1, 4, 7, + 4, 5, 7, + 6, 7, 8 +]; + +Tables.t3l = [ + 2, 3, 7, + 4, 4, 7, + 6, 7, 8 +]; + +Tables.t5l = [ + 1, 4, 7, 8, + 4, 5, 8, 9, + 7, 8, 9, 10, + 8, 8, 9, 10 +]; + +Tables.t6l = [ + 3, 4, 6, 8, + 4, 4, 6, 7, + 5, 6, 7, 8, + 7, 7, 8, 9 +]; + +Tables.t7l = [ + 1, 4, 7, 9, 9, 10, + 4, 6, 8, 9, 9, 10, + 7, 7, 9, 10, 10, 11, + 8, 9, 10, 11, 11, 11, + 8, 9, 10, 11, 11, 12, + 9, 10, 11, 12, 12, 12 +]; + +Tables.t8l = [ + 2, 4, 7, 9, 9, 10, + 4, 4, 6, 10, 10, 10, + 7, 6, 8, 10, 10, 11, + 9, 10, 10, 11, 11, 12, + 9, 9, 10, 11, 12, 12, + 10, 10, 11, 11, 13, 13 +]; + +Tables.t9l = [ + 3, 4, 6, 7, 9, 10, + 4, 5, 6, 7, 8, 10, + 5, 6, 7, 8, 9, 10, + 7, 7, 8, 9, 9, 10, + 8, 8, 9, 9, 10, 11, + 9, 9, 10, 10, 11, 11 +]; + +Tables.t10l = [ + 1, 4, 7, 9, 10, 10, 10, 11, + 4, 6, 8, 9, 10, 11, 10, 10, + 7, 8, 9, 10, 11, 12, 11, 11, + 8, 9, 10, 11, 12, 12, 11, 12, + 9, 10, 11, 12, 12, 12, 12, 12, + 10, 11, 12, 12, 13, 13, 12, 13, + 9, 10, 11, 12, 12, 12, 13, 13, + 10, 10, 11, 12, 12, 13, 13, 13 +]; + +Tables.t11l = [ + 2, 4, 6, 8, 9, 10, 9, 10, + 4, 5, 6, 8, 10, 10, 9, 10, + 6, 7, 8, 9, 10, 11, 10, 10, + 8, 8, 9, 11, 10, 12, 10, 11, + 9, 10, 10, 11, 11, 12, 11, 12, + 9, 10, 11, 12, 12, 13, 12, 13, + 9, 9, 9, 10, 11, 12, 12, 12, + 9, 9, 10, 11, 12, 12, 12, 12 +]; + +Tables.t12l = [ + 4, 4, 6, 8, 9, 10, 10, 10, + 4, 5, 6, 7, 9, 9, 10, 10, + 6, 6, 7, 8, 9, 10, 9, 10, + 7, 7, 8, 8, 9, 10, 10, 10, + 8, 8, 9, 9, 10, 10, 10, 11, + 9, 9, 10, 10, 10, 11, 10, 11, + 9, 9, 9, 10, 10, 11, 11, 12, + 10, 10, 10, 11, 11, 11, 11, 12 +]; + +Tables.t13l = [ + 1, 5, 7, 8, 9, 10, 10, 11, 10, 11, 12, 12, 13, 13, 14, 14, + 4, 6, 8, 9, 10, 10, 11, 11, 11, 11, 12, 12, 13, 14, 14, 14, + 7, 8, 9, 10, 11, 11, 12, 12, 11, 12, 12, 13, 13, 14, 15, 15, + 8, 9, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 15, 15, + 9, 9, 11, 11, 12, 12, 13, 13, 12, 13, 13, 14, 14, 15, 15, 16, + 10, 10, 11, 12, 12, 12, 13, 13, 13, 13, 14, 13, 15, 15, 16, 16, + 10, 11, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, + 11, 11, 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 16, 18, 18, + 10, 10, 11, 12, 12, 13, 13, 14, 14, 14, 14, 15, 15, 16, 17, 17, + 11, 11, 12, 12, 13, 13, 13, 15, 14, 15, 15, 16, 16, 16, 18, 17, + 11, 12, 12, 13, 13, 14, 14, 15, 14, 15, 16, 15, 16, 17, 18, 19, + 12, 12, 12, 13, 14, 14, 14, 14, 15, 15, 15, 16, 17, 17, 17, 18, + 12, 13, 13, 14, 14, 15, 14, 15, 16, 16, 17, 17, 17, 18, 18, 18, + 13, 13, 14, 15, 15, 15, 16, 16, 16, 16, 16, 17, 18, 17, 18, 18, + 14, 14, 14, 15, 15, 15, 17, 16, 16, 19, 17, 17, 17, 19, 18, 18, + 13, 14, 15, 16, 16, 16, 17, 16, 17, 17, 18, 18, 21, 20, 21, 18 +]; + +Tables.t15l = [ + 3, 5, 6, 8, 8, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 14, + 5, 5, 7, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, + 6, 7, 7, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 13, + 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, + 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, + 9, 9, 9, 10, 10, 10, 11, 11, 11, 11, 12, 12, 13, 13, 13, 14, + 10, 9, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 14, 14, + 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 14, + 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 14, 14, + 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, + 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 15, 14, + 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, + 12, 12, 11, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 15, 15, + 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, + 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 14, 15, + 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15 +]; + +Tables.t16_5l = [ + 1, 5, 7, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 11, + 4, 6, 8, 9, 10, 11, 11, 11, 12, 12, 12, 13, 14, 13, 14, 11, + 7, 8, 9, 10, 11, 11, 12, 12, 13, 12, 13, 13, 13, 14, 14, 12, + 9, 9, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 13, + 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 12, + 10, 10, 11, 11, 12, 13, 13, 14, 13, 14, 14, 15, 15, 15, 16, 13, + 11, 11, 11, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 16, 13, + 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 17, 17, 13, + 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 13, + 12, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 15, 16, 15, 14, + 12, 13, 12, 13, 14, 14, 14, 14, 15, 16, 16, 16, 17, 17, 16, 13, + 13, 13, 13, 13, 14, 14, 15, 16, 16, 16, 16, 16, 16, 15, 16, 14, + 13, 14, 14, 14, 14, 15, 15, 15, 15, 17, 16, 16, 16, 16, 18, 14, + 15, 14, 14, 14, 15, 15, 16, 16, 16, 18, 17, 17, 17, 19, 17, 14, + 14, 15, 13, 14, 16, 16, 15, 16, 16, 17, 18, 17, 19, 17, 16, 14, + 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 12 +]; + +Tables.t16l = [ + 1, 5, 7, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 10, + 4, 6, 8, 9, 10, 11, 11, 11, 12, 12, 12, 13, 14, 13, 14, 10, + 7, 8, 9, 10, 11, 11, 12, 12, 13, 12, 13, 13, 13, 14, 14, 11, + 9, 9, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 12, + 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 11, + 10, 10, 11, 11, 12, 13, 13, 14, 13, 14, 14, 15, 15, 15, 16, 12, + 11, 11, 11, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 16, 12, + 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 17, 17, 12, + 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 12, + 12, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 15, 16, 15, 13, + 12, 13, 12, 13, 14, 14, 14, 14, 15, 16, 16, 16, 17, 17, 16, 12, + 13, 13, 13, 13, 14, 14, 15, 16, 16, 16, 16, 16, 16, 15, 16, 13, + 13, 14, 14, 14, 14, 15, 15, 15, 15, 17, 16, 16, 16, 16, 18, 13, + 15, 14, 14, 14, 15, 15, 16, 16, 16, 18, 17, 17, 17, 19, 17, 13, + 14, 15, 13, 14, 16, 16, 15, 16, 16, 17, 18, 17, 19, 17, 16, 13, + 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 10 +]; + +Tables.t24l = [ + 4, 5, 7, 8, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 13, 10, + 5, 6, 7, 8, 9, 10, 10, 11, 11, 11, 12, 12, 12, 12, 12, 10, + 7, 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 9, + 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 9, + 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 9, + 10, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 9, + 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 9, + 11, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 10, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 10, + 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 10, + 12, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 10, + 12, 12, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 10, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 10, + 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 10, + 13, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 10, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 6 +]; + +Tables.t32l = [ + 1 + 0, 4 + 1, 4 + 1, 5 + 2, 4 + 1, 6 + 2, 5 + 2, 6 + 3, + 4 + 1, 5 + 2, 5 + 2, 6 + 3, 5 + 2, 6 + 3, 6 + 3, 6 + 4 +]; + +Tables.t33l = [ + 4 + 0, 4 + 1, 4 + 1, 4 + 2, 4 + 1, 4 + 2, 4 + 2, 4 + 3, + 4 + 1, 4 + 2, 4 + 2, 4 + 3, 4 + 2, 4 + 3, 4 + 3, 4 + 4 +]; + +Tables.ht = [ + /* xlen, linmax, table, hlen */ + new HuffCodeTab(0, 0, null, null), + new HuffCodeTab(2, 0, Tables.t1HB, Tables.t1l), + new HuffCodeTab(3, 0, Tables.t2HB, Tables.t2l), + new HuffCodeTab(3, 0, Tables.t3HB, Tables.t3l), + new HuffCodeTab(0, 0, null, null), /* Apparently not used */ + new HuffCodeTab(4, 0, Tables.t5HB, Tables.t5l), + new HuffCodeTab(4, 0, Tables.t6HB, Tables.t6l), + new HuffCodeTab(6, 0, Tables.t7HB, Tables.t7l), + new HuffCodeTab(6, 0, Tables.t8HB, Tables.t8l), + new HuffCodeTab(6, 0, Tables.t9HB, Tables.t9l), + new HuffCodeTab(8, 0, Tables.t10HB, Tables.t10l), + new HuffCodeTab(8, 0, Tables.t11HB, Tables.t11l), + new HuffCodeTab(8, 0, Tables.t12HB, Tables.t12l), + new HuffCodeTab(16, 0, Tables.t13HB, Tables.t13l), + new HuffCodeTab(0, 0, null, Tables.t16_5l), /* Apparently not used */ + new HuffCodeTab(16, 0, Tables.t15HB, Tables.t15l), + + new HuffCodeTab(1, 1, Tables.t16HB, Tables.t16l), + new HuffCodeTab(2, 3, Tables.t16HB, Tables.t16l), + new HuffCodeTab(3, 7, Tables.t16HB, Tables.t16l), + new HuffCodeTab(4, 15, Tables.t16HB, Tables.t16l), + new HuffCodeTab(6, 63, Tables.t16HB, Tables.t16l), + new HuffCodeTab(8, 255, Tables.t16HB, Tables.t16l), + new HuffCodeTab(10, 1023, Tables.t16HB, Tables.t16l), + new HuffCodeTab(13, 8191, Tables.t16HB, Tables.t16l), + + new HuffCodeTab(4, 15, Tables.t24HB, Tables.t24l), + new HuffCodeTab(5, 31, Tables.t24HB, Tables.t24l), + new HuffCodeTab(6, 63, Tables.t24HB, Tables.t24l), + new HuffCodeTab(7, 127, Tables.t24HB, Tables.t24l), + new HuffCodeTab(8, 255, Tables.t24HB, Tables.t24l), + new HuffCodeTab(9, 511, Tables.t24HB, Tables.t24l), + new HuffCodeTab(11, 2047, Tables.t24HB, Tables.t24l), + new HuffCodeTab(13, 8191, Tables.t24HB, Tables.t24l), + + new HuffCodeTab(0, 0, Tables.t32HB, Tables.t32l), + new HuffCodeTab(0, 0, Tables.t33HB, Tables.t33l), +]; + +/** + * + * for (i = 0; i < 16*16; i++) [ + * largetbl[i] = ((ht[16].hlen[i]) << 16) + ht[24].hlen[i]; + * ] + * + * + */ +Tables.largetbl = [ + 0x010004, 0x050005, 0x070007, 0x090008, 0x0a0009, 0x0a000a, 0x0b000a, 0x0b000b, + 0x0c000b, 0x0c000c, 0x0c000c, 0x0d000c, 0x0d000c, 0x0d000c, 0x0e000d, 0x0a000a, + 0x040005, 0x060006, 0x080007, 0x090008, 0x0a0009, 0x0b000a, 0x0b000a, 0x0b000b, + 0x0c000b, 0x0c000b, 0x0c000c, 0x0d000c, 0x0e000c, 0x0d000c, 0x0e000c, 0x0a000a, + 0x070007, 0x080007, 0x090008, 0x0a0009, 0x0b0009, 0x0b000a, 0x0c000a, 0x0c000b, + 0x0d000b, 0x0c000b, 0x0d000b, 0x0d000c, 0x0d000c, 0x0e000c, 0x0e000d, 0x0b0009, + 0x090008, 0x090008, 0x0a0009, 0x0b0009, 0x0b000a, 0x0c000a, 0x0c000a, 0x0c000b, + 0x0d000b, 0x0d000b, 0x0e000b, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x0c0009, + 0x0a0009, 0x0a0009, 0x0b0009, 0x0b000a, 0x0c000a, 0x0c000a, 0x0d000a, 0x0d000b, + 0x0d000b, 0x0e000b, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x0f000d, 0x0b0009, + 0x0a000a, 0x0a0009, 0x0b000a, 0x0b000a, 0x0c000a, 0x0d000a, 0x0d000b, 0x0e000b, + 0x0d000b, 0x0e000b, 0x0e000c, 0x0f000c, 0x0f000c, 0x0f000c, 0x10000c, 0x0c0009, + 0x0b000a, 0x0b000a, 0x0b000a, 0x0c000a, 0x0d000a, 0x0d000b, 0x0d000b, 0x0d000b, + 0x0e000b, 0x0e000c, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x10000d, 0x0c0009, + 0x0b000b, 0x0b000a, 0x0c000a, 0x0c000a, 0x0d000b, 0x0d000b, 0x0d000b, 0x0e000b, + 0x0e000c, 0x0f000c, 0x0f000c, 0x0f000c, 0x0f000c, 0x11000d, 0x11000d, 0x0c000a, + 0x0b000b, 0x0c000b, 0x0c000b, 0x0d000b, 0x0d000b, 0x0d000b, 0x0e000b, 0x0e000b, + 0x0f000b, 0x0f000c, 0x0f000c, 0x0f000c, 0x10000c, 0x10000d, 0x10000d, 0x0c000a, + 0x0c000b, 0x0c000b, 0x0c000b, 0x0d000b, 0x0d000b, 0x0e000b, 0x0e000b, 0x0f000c, + 0x0f000c, 0x0f000c, 0x0f000c, 0x10000c, 0x0f000d, 0x10000d, 0x0f000d, 0x0d000a, + 0x0c000c, 0x0d000b, 0x0c000b, 0x0d000b, 0x0e000b, 0x0e000c, 0x0e000c, 0x0e000c, + 0x0f000c, 0x10000c, 0x10000c, 0x10000d, 0x11000d, 0x11000d, 0x10000d, 0x0c000a, + 0x0d000c, 0x0d000c, 0x0d000b, 0x0d000b, 0x0e000b, 0x0e000c, 0x0f000c, 0x10000c, + 0x10000c, 0x10000c, 0x10000c, 0x10000d, 0x10000d, 0x0f000d, 0x10000d, 0x0d000a, + 0x0d000c, 0x0e000c, 0x0e000c, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x0f000c, + 0x0f000c, 0x11000c, 0x10000d, 0x10000d, 0x10000d, 0x10000d, 0x12000d, 0x0d000a, + 0x0f000c, 0x0e000c, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x10000c, 0x10000c, + 0x10000d, 0x12000d, 0x11000d, 0x11000d, 0x11000d, 0x13000d, 0x11000d, 0x0d000a, + 0x0e000d, 0x0f000c, 0x0d000c, 0x0e000c, 0x10000c, 0x10000c, 0x0f000c, 0x10000d, + 0x10000d, 0x11000d, 0x12000d, 0x11000d, 0x13000d, 0x11000d, 0x10000d, 0x0d000a, + 0x0a0009, 0x0a0009, 0x0a0009, 0x0b0009, 0x0b0009, 0x0c0009, 0x0c0009, 0x0c0009, + 0x0d0009, 0x0d0009, 0x0d0009, 0x0d000a, 0x0d000a, 0x0d000a, 0x0d000a, 0x0a0006 +]; +/** + * + * for (i = 0; i < 3*3; i++) [ + * table23[i] = ((ht[2].hlen[i]) << 16) + ht[3].hlen[i]; + * ] + * + * + */ +Tables.table23 = [ + 0x010002, 0x040003, 0x070007, + 0x040004, 0x050004, 0x070007, + 0x060006, 0x070007, 0x080008 +]; + +/** + * + * for (i = 0; i < 4*4; i++) [ + * table56[i] = ((ht[5].hlen[i]) << 16) + ht[6].hlen[i]; + * ] + * + * + */ +Tables.table56 = [ + 0x010003, 0x040004, 0x070006, 0x080008, 0x040004, 0x050004, 0x080006, 0x090007, + 0x070005, 0x080006, 0x090007, 0x0a0008, 0x080007, 0x080007, 0x090008, 0x0a0009 +]; + +Tables.bitrate_table = [ + [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1], /* MPEG 2 */ + [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1], /* MPEG 1 */ + [0, 8, 16, 24, 32, 40, 48, 56, 64, -1, -1, -1, -1, -1, -1, -1], /* MPEG 2.5 */ +]; + +/** + * MPEG 2, MPEG 1, MPEG 2.5. + */ +Tables.samplerate_table = [ + [22050, 24000, 16000, -1], + [44100, 48000, 32000, -1], + [11025, 12000, 8000, -1], +]; + +/** + * This is the scfsi_band table from 2.4.2.7 of the IS. + */ +Tables.scfsi_band = [0, 6, 11, 16, 21]; + +function MeanBits(meanBits) { + this.bits = meanBits; +} + +//package mp3; + +function CalcNoiseResult() { + /** + * sum of quantization noise > masking + */ + this.over_noise = 0.; + /** + * sum of all quantization noise + */ + this.tot_noise = 0.; + /** + * max quantization noise + */ + this.max_noise = 0.; + /** + * number of quantization noise > masking + */ + this.over_count = 0; + /** + * SSD-like cost of distorted bands + */ + this.over_SSD = 0; + this.bits = 0; +} + +function VBRQuantize() { + var qupvt; + var tak; + + this.setModules = function (_qupvt, _tk) { + qupvt = _qupvt; + tak = _tk; + } + //TODO + +} + + + +/** + * ATH related stuff, if something new ATH related has to be added, please plug + * it here into the ATH. + */ +function ATH() { + /** + * Method for the auto adjustment. + */ + this.useAdjust = 0; + /** + * factor for tuning the (sample power) point below which adaptive threshold + * of hearing adjustment occurs + */ + this.aaSensitivityP = 0.; + /** + * Lowering based on peak volume, 1 = no lowering. + */ + this.adjust = 0.; + /** + * Limit for dynamic ATH adjust. + */ + this.adjustLimit = 0.; + /** + * Determined to lower x dB each second. + */ + this.decay = 0.; + /** + * Lowest ATH value. + */ + this.floor = 0.; + /** + * ATH for sfbs in long blocks. + */ + this.l = new_float(Encoder.SBMAX_l); + /** + * ATH for sfbs in short blocks. + */ + this.s = new_float(Encoder.SBMAX_s); + /** + * ATH for partitioned sfb21 in long blocks. + */ + this.psfb21 = new_float(Encoder.PSFB21); + /** + * ATH for partitioned sfb12 in short blocks. + */ + this.psfb12 = new_float(Encoder.PSFB12); + /** + * ATH for long block convolution bands. + */ + this.cb_l = new_float(Encoder.CBANDS); + /** + * ATH for short block convolution bands. + */ + this.cb_s = new_float(Encoder.CBANDS); + /** + * Equal loudness weights (based on ATH). + */ + this.eql_w = new_float(Encoder.BLKSIZE / 2); +} + + +function LameGlobalFlags() { + + this.class_id = 0; + + /* input description */ + + /** + * number of samples. default=-1 + */ + this.num_samples = 0; + /** + * input number of channels. default=2 + */ + this.num_channels = 0; + /** + * input_samp_rate in Hz. default=44.1 kHz + */ + this.in_samplerate = 0; + /** + * output_samp_rate. default: LAME picks best value at least not used for + * MP3 decoding: Remember 44.1 kHz MP3s and AC97 + */ + this.out_samplerate = 0; + /** + * scale input by this amount before encoding at least not used for MP3 + * decoding + */ + this.scale = 0.; + /** + * scale input of channel 0 (left) by this amount before encoding + */ + this.scale_left = 0.; + /** + * scale input of channel 1 (right) by this amount before encoding + */ + this.scale_right = 0.; + + /* general control params */ + /** + * collect data for a MP3 frame analyzer? + */ + this.analysis = false; + /** + * add Xing VBR tag? + */ + this.bWriteVbrTag = false; + + /** + * use lame/mpglib to convert mp3 to wav + */ + this.decode_only = false; + /** + * quality setting 0=best, 9=worst default=5 + */ + this.quality = 0; + /** + * see enum default = LAME picks best value + */ + this.mode = MPEGMode.STEREO; + /** + * force M/S mode. requires mode=1 + */ + this.force_ms = false; + /** + * use free format? default=0 + */ + this.free_format = false; + /** + * find the RG value? default=0 + */ + this.findReplayGain = false; + /** + * decode on the fly? default=0 + */ + this.decode_on_the_fly = false; + /** + * 1 (default) writes ID3 tags, 0 not + */ + this.write_id3tag_automatic = false; + + /* + * set either brate>0 or compression_ratio>0, LAME will compute the value of + * the variable not set. Default is compression_ratio = 11.025 + */ + /** + * bitrate + */ + this.brate = 0; + /** + * sizeof(wav file)/sizeof(mp3 file) + */ + this.compression_ratio = 0.; + + /* frame params */ + /** + * mark as copyright. default=0 + */ + this.copyright = 0; + /** + * mark as original. default=1 + */ + this.original = 0; + /** + * the MP3 'private extension' bit. Meaningless + */ + this.extension = 0; + /** + * Input PCM is emphased PCM (for instance from one of the rarely emphased + * CDs), it is STRONGLY not recommended to use this, because psycho does not + * take it into account, and last but not least many decoders don't care + * about these bits + */ + this.emphasis = 0; + /** + * use 2 bytes per frame for a CRC checksum. default=0 + */ + this.error_protection = 0; + /** + * enforce ISO spec as much as possible + */ + this.strict_ISO = false; + + /** + * use bit reservoir? + */ + this.disable_reservoir = false; + + /* quantization/noise shaping */ + this.quant_comp = 0; + this.quant_comp_short = 0; + this.experimentalY = false; + this.experimentalZ = 0; + this.exp_nspsytune = 0; + + this.preset = 0; + + /* VBR control */ + this.VBR = null; + /** + * Range [0,...,1[ + */ + this.VBR_q_frac = 0.; + /** + * Range [0,...,9] + */ + this.VBR_q = 0; + this.VBR_mean_bitrate_kbps = 0; + this.VBR_min_bitrate_kbps = 0; + this.VBR_max_bitrate_kbps = 0; + /** + * strictly enforce VBR_min_bitrate normaly, it will be violated for analog + * silence + */ + this.VBR_hard_min = 0; + + /* resampling and filtering */ + + /** + * freq in Hz. 0=lame choses. -1=no filter + */ + this.lowpassfreq = 0; + /** + * freq in Hz. 0=lame choses. -1=no filter + */ + this.highpassfreq = 0; + /** + * freq width of filter, in Hz (default=15%) + */ + this.lowpasswidth = 0; + /** + * freq width of filter, in Hz (default=15%) + */ + this.highpasswidth = 0; + + /* + * psycho acoustics and other arguments which you should not change unless + * you know what you are doing + */ + + this.maskingadjust = 0.; + this.maskingadjust_short = 0.; + /** + * only use ATH + */ + this.ATHonly = false; + /** + * only use ATH for short blocks + */ + this.ATHshort = false; + /** + * disable ATH + */ + this.noATH = false; + /** + * select ATH formula + */ + this.ATHtype = 0; + /** + * change ATH formula 4 shape + */ + this.ATHcurve = 0.; + /** + * lower ATH by this many db + */ + this.ATHlower = 0.; + /** + * select ATH auto-adjust scheme + */ + this.athaa_type = 0; + /** + * select ATH auto-adjust loudness calc + */ + this.athaa_loudapprox = 0; + /** + * dB, tune active region of auto-level + */ + this.athaa_sensitivity = 0.; + this.short_blocks = null; + /** + * use temporal masking effect + */ + this.useTemporal = false; + this.interChRatio = 0.; + /** + * Naoki's adjustment of Mid/Side maskings + */ + this.msfix = 0.; + + /** + * 0 off, 1 on + */ + this.tune = false; + /** + * used to pass values for debugging and stuff + */ + this.tune_value_a = 0.; + + /************************************************************************/ + /* internal variables, do not set... */ + /* provided because they may be of use to calling application */ + /************************************************************************/ + + /** + * 0=MPEG-2/2.5 1=MPEG-1 + */ + this.version = 0; + this.encoder_delay = 0; + /** + * number of samples of padding appended to input + */ + this.encoder_padding = 0; + this.framesize = 0; + /** + * number of frames encoded + */ + this.frameNum = 0; + /** + * is this struct owned by calling program or lame? + */ + this.lame_allocated_gfp = 0; + /**************************************************************************/ + /* more internal variables are stored in this structure: */ + /**************************************************************************/ + this.internal_flags = null; +} + + + +function CBRNewIterationLoop(_quantize) { + var quantize = _quantize; + this.quantize = quantize; + this.iteration_loop = function(gfp, pe, ms_ener_ratio, ratio) { + var gfc = gfp.internal_flags; + var l3_xmin = new_float(L3Side.SFBMAX); + var xrpow = new_float(576); + var targ_bits = new_int(2); + var mean_bits = 0, max_bits; + var l3_side = gfc.l3_side; + + var mb = new MeanBits(mean_bits); + this.quantize.rv.ResvFrameBegin(gfp, mb); + mean_bits = mb.bits; + + /* quantize! */ + for (var gr = 0; gr < gfc.mode_gr; gr++) { + + /* + * calculate needed bits + */ + max_bits = this.quantize.qupvt.on_pe(gfp, pe, targ_bits, mean_bits, + gr, gr); + + if (gfc.mode_ext == Encoder.MPG_MD_MS_LR) { + this.quantize.ms_convert(gfc.l3_side, gr); + this.quantize.qupvt.reduce_side(targ_bits, ms_ener_ratio[gr], + mean_bits, max_bits); + } + + for (var ch = 0; ch < gfc.channels_out; ch++) { + var adjust, masking_lower_db; + var cod_info = l3_side.tt[gr][ch]; + + if (cod_info.block_type != Encoder.SHORT_TYPE) { + // NORM, START or STOP type + adjust = 0; + masking_lower_db = gfc.PSY.mask_adjust - adjust; + } else { + adjust = 0; + masking_lower_db = gfc.PSY.mask_adjust_short - adjust; + } + gfc.masking_lower = Math.pow(10.0, + masking_lower_db * 0.1); + + /* + * init_outer_loop sets up cod_info, scalefac and xrpow + */ + this.quantize.init_outer_loop(gfc, cod_info); + if (this.quantize.init_xrpow(gfc, cod_info, xrpow)) { + /* + * xr contains energy we will have to encode calculate the + * masking abilities find some good quantization in + * outer_loop + */ + this.quantize.qupvt.calc_xmin(gfp, ratio[gr][ch], cod_info, + l3_xmin); + this.quantize.outer_loop(gfp, cod_info, l3_xmin, xrpow, ch, + targ_bits[ch]); + } + + this.quantize.iteration_finish_one(gfc, gr, ch); + } /* for ch */ + } /* for gr */ + + this.quantize.rv.ResvFrameEnd(gfc, mean_bits); + } +} + + +function ReplayGain() { + this.linprebuf = new_float(GainAnalysis.MAX_ORDER * 2); + /** + * left input samples, with pre-buffer + */ + this.linpre = 0; + this.lstepbuf = new_float(GainAnalysis.MAX_SAMPLES_PER_WINDOW + GainAnalysis.MAX_ORDER); + /** + * left "first step" (i.e. post first filter) samples + */ + this.lstep = 0; + this.loutbuf = new_float(GainAnalysis.MAX_SAMPLES_PER_WINDOW + GainAnalysis.MAX_ORDER); + /** + * left "out" (i.e. post second filter) samples + */ + this.lout = 0; + this.rinprebuf = new_float(GainAnalysis.MAX_ORDER * 2); + /** + * right input samples ... + */ + this.rinpre = 0; + this.rstepbuf = new_float(GainAnalysis.MAX_SAMPLES_PER_WINDOW + GainAnalysis.MAX_ORDER); + this.rstep = 0; + this.routbuf = new_float(GainAnalysis.MAX_SAMPLES_PER_WINDOW + GainAnalysis.MAX_ORDER); + this.rout = 0; + /** + * number of samples required to reach number of milliseconds required + * for RMS window + */ + this.sampleWindow = 0; + this.totsamp = 0; + this.lsum = 0.; + this.rsum = 0.; + this.freqindex = 0; + this.first = 0; + this.A = new_int(0 | (GainAnalysis.STEPS_per_dB * GainAnalysis.MAX_dB)); + this.B = new_int(0 | (GainAnalysis.STEPS_per_dB * GainAnalysis.MAX_dB)); + +} + +//package mp3; + +/** + * Layer III side information. + * + * @author Ken + * + */ + + + +function ScaleFac(arrL, arrS, arr21, arr12) { + + this.l = new_int(1 + Encoder.SBMAX_l); + this.s = new_int(1 + Encoder.SBMAX_s); + this.psfb21 = new_int(1 + Encoder.PSFB21); + this.psfb12 = new_int(1 + Encoder.PSFB12); + var l = this.l; + var s = this.s; + + if (arguments.length == 4) { + //public ScaleFac(final int[] arrL, final int[] arrS, final int[] arr21, + // final int[] arr12) { + this.arrL = arguments[0]; + this.arrS = arguments[1]; + this.arr21 = arguments[2]; + this.arr12 = arguments[3]; + + System.arraycopy(this.arrL, 0, l, 0, Math.min(this.arrL.length, this.l.length)); + System.arraycopy(this.arrS, 0, s, 0, Math.min(this.arrS.length, this.s.length)); + System.arraycopy(this.arr21, 0, this.psfb21, 0, Math.min(this.arr21.length, this.psfb21.length)); + System.arraycopy(this.arr12, 0, this.psfb12, 0, Math.min(this.arr12.length, this.psfb12.length)); + } +} + +/* + * quantize_pvt source file + * + * Copyright (c) 1999-2002 Takehiro Tominaga + * Copyright (c) 2000-2002 Robert Hegemann + * Copyright (c) 2001 Naoki Shibata + * Copyright (c) 2002-2005 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: QuantizePVT.java,v 1.24 2011/05/24 20:48:06 kenchis Exp $ */ + + +QuantizePVT.Q_MAX = (256 + 1); +QuantizePVT.Q_MAX2 = 116; +QuantizePVT.LARGE_BITS = 100000; +QuantizePVT.IXMAX_VAL = 8206; + +function QuantizePVT() { + + var tak = null; + var rv = null; + var psy = null; + + this.setModules = function (_tk, _rv, _psy) { + tak = _tk; + rv = _rv; + psy = _psy; + }; + + function POW20(x) { + return pow20[x + QuantizePVT.Q_MAX2]; + } + + this.IPOW20 = function (x) { + return ipow20[x]; + } + + /** + * smallest such that 1.0+DBL_EPSILON != 1.0 + */ + var DBL_EPSILON = 2.2204460492503131e-016; + + /** + * ix always <= 8191+15. see count_bits() + */ + var IXMAX_VAL = QuantizePVT.IXMAX_VAL; + + var PRECALC_SIZE = (IXMAX_VAL + 2); + + var Q_MAX = QuantizePVT.Q_MAX; + + + /** + * + * minimum possible number of + * -cod_info.global_gain + ((scalefac[] + (cod_info.preflag ? pretab[sfb] : 0)) + * << (cod_info.scalefac_scale + 1)) + cod_info.subblock_gain[cod_info.window[sfb]] * 8; + * + * for long block, 0+((15+3)<<2) = 18*4 = 72 + * for short block, 0+(15<<2)+7*8 = 15*4+56 = 116 + * + */ + var Q_MAX2 = QuantizePVT.Q_MAX2; + + var LARGE_BITS = QuantizePVT.LARGE_BITS; + + + /** + * Assuming dynamic range=96dB, this value should be 92 + */ + var NSATHSCALE = 100; + + /** + * The following table is used to implement the scalefactor partitioning for + * MPEG2 as described in section 2.4.3.2 of the IS. The indexing corresponds + * to the way the tables are presented in the IS: + * + * [table_number][row_in_table][column of nr_of_sfb] + */ + this.nr_of_sfb_block = [ + [[6, 5, 5, 5], [9, 9, 9, 9], [6, 9, 9, 9]], + [[6, 5, 7, 3], [9, 9, 12, 6], [6, 9, 12, 6]], + [[11, 10, 0, 0], [18, 18, 0, 0], [15, 18, 0, 0]], + [[7, 7, 7, 0], [12, 12, 12, 0], [6, 15, 12, 0]], + [[6, 6, 6, 3], [12, 9, 9, 6], [6, 12, 9, 6]], + [[8, 8, 5, 0], [15, 12, 9, 0], [6, 18, 9, 0]]]; + + /** + * Table B.6: layer3 preemphasis + */ + var pretab = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 2, 2, 3, 3, 3, 2, 0]; + this.pretab = pretab; + + /** + * Here are MPEG1 Table B.8 and MPEG2 Table B.1 -- Layer III scalefactor + * bands.
+ * Index into this using a method such as:
+ * idx = fr_ps.header.sampling_frequency + (fr_ps.header.version * 3) + */ + this.sfBandIndex = [ + // Table B.2.b: 22.05 kHz + new ScaleFac([0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, + 522, 576], + [0, 4, 8, 12, 18, 24, 32, 42, 56, 74, 100, 132, 174, 192] + , [0, 0, 0, 0, 0, 0, 0] // sfb21 pseudo sub bands + , [0, 0, 0, 0, 0, 0, 0] // sfb12 pseudo sub bands + ), + /* Table B.2.c: 24 kHz */ /* docs: 332. mpg123(broken): 330 */ + new ScaleFac([0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 114, 136, 162, 194, 232, 278, 332, 394, 464, + 540, 576], + [0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 136, 180, 192] + , [0, 0, 0, 0, 0, 0, 0] /* sfb21 pseudo sub bands */ + , [0, 0, 0, 0, 0, 0, 0] /* sfb12 pseudo sub bands */ + ), + /* Table B.2.a: 16 kHz */ + new ScaleFac([0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, + 522, 576], + [0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192] + , [0, 0, 0, 0, 0, 0, 0] /* sfb21 pseudo sub bands */ + , [0, 0, 0, 0, 0, 0, 0] /* sfb12 pseudo sub bands */ + ), + /* Table B.8.b: 44.1 kHz */ + new ScaleFac([0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, + 576], + [0, 4, 8, 12, 16, 22, 30, 40, 52, 66, 84, 106, 136, 192] + , [0, 0, 0, 0, 0, 0, 0] /* sfb21 pseudo sub bands */ + , [0, 0, 0, 0, 0, 0, 0] /* sfb12 pseudo sub bands */ + ), + /* Table B.8.c: 48 kHz */ + new ScaleFac([0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, + 576], + [0, 4, 8, 12, 16, 22, 28, 38, 50, 64, 80, 100, 126, 192] + , [0, 0, 0, 0, 0, 0, 0] /* sfb21 pseudo sub bands */ + , [0, 0, 0, 0, 0, 0, 0] /* sfb12 pseudo sub bands */ + ), + /* Table B.8.a: 32 kHz */ + new ScaleFac([0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, + 576], + [0, 4, 8, 12, 16, 22, 30, 42, 58, 78, 104, 138, 180, 192] + , [0, 0, 0, 0, 0, 0, 0] /* sfb21 pseudo sub bands */ + , [0, 0, 0, 0, 0, 0, 0] /* sfb12 pseudo sub bands */ + ), + /* MPEG-2.5 11.025 kHz */ + new ScaleFac([0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, + 522, 576], + [0 / 3, 12 / 3, 24 / 3, 36 / 3, 54 / 3, 78 / 3, 108 / 3, 144 / 3, 186 / 3, 240 / 3, 312 / 3, + 402 / 3, 522 / 3, 576 / 3] + , [0, 0, 0, 0, 0, 0, 0] /* sfb21 pseudo sub bands */ + , [0, 0, 0, 0, 0, 0, 0] /* sfb12 pseudo sub bands */ + ), + /* MPEG-2.5 12 kHz */ + new ScaleFac([0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, + 522, 576], + [0 / 3, 12 / 3, 24 / 3, 36 / 3, 54 / 3, 78 / 3, 108 / 3, 144 / 3, 186 / 3, 240 / 3, 312 / 3, + 402 / 3, 522 / 3, 576 / 3] + , [0, 0, 0, 0, 0, 0, 0] /* sfb21 pseudo sub bands */ + , [0, 0, 0, 0, 0, 0, 0] /* sfb12 pseudo sub bands */ + ), + /* MPEG-2.5 8 kHz */ + new ScaleFac([0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, 232, 280, 336, 400, 476, 566, 568, 570, + 572, 574, 576], + [0 / 3, 24 / 3, 48 / 3, 72 / 3, 108 / 3, 156 / 3, 216 / 3, 288 / 3, 372 / 3, 480 / 3, 486 / 3, + 492 / 3, 498 / 3, 576 / 3] + , [0, 0, 0, 0, 0, 0, 0] /* sfb21 pseudo sub bands */ + , [0, 0, 0, 0, 0, 0, 0] /* sfb12 pseudo sub bands */ + ) + ]; + + var pow20 = new_float(Q_MAX + Q_MAX2 + 1); + var ipow20 = new_float(Q_MAX); + var pow43 = new_float(PRECALC_SIZE); + + var adj43 = new_float(PRECALC_SIZE); + this.adj43 = adj43; + + /** + *
+     * compute the ATH for each scalefactor band cd range: 0..96db
+     *
+     * Input: 3.3kHz signal 32767 amplitude (3.3kHz is where ATH is smallest =
+     * -5db) longblocks: sfb=12 en0/bw=-11db max_en0 = 1.3db shortblocks: sfb=5
+     * -9db 0db
+     *
+     * Input: 1 1 1 1 1 1 1 -1 -1 -1 -1 -1 -1 -1 (repeated) longblocks: amp=1
+     * sfb=12 en0/bw=-103 db max_en0 = -92db amp=32767 sfb=12 -12 db -1.4db
+     *
+     * Input: 1 1 1 1 1 1 1 -1 -1 -1 -1 -1 -1 -1 (repeated) shortblocks: amp=1
+     * sfb=5 en0/bw= -99 -86 amp=32767 sfb=5 -9 db 4db
+     *
+     *
+     * MAX energy of largest wave at 3.3kHz = 1db AVE energy of largest wave at
+     * 3.3kHz = -11db Let's take AVE: -11db = maximum signal in sfb=12. Dynamic
+     * range of CD: 96db. Therefor energy of smallest audible wave in sfb=12 =
+     * -11 - 96 = -107db = ATH at 3.3kHz.
+     *
+     * ATH formula for this wave: -5db. To adjust to LAME scaling, we need ATH =
+     * ATH_formula - 103 (db) ATH = ATH * 2.5e-10 (ener)
+     * 
+ */ + function ATHmdct(gfp, f) { + var ath = psy.ATHformula(f, gfp); + + ath -= NSATHSCALE; + + /* modify the MDCT scaling for the ATH and convert to energy */ + ath = Math.pow(10.0, ath / 10.0 + gfp.ATHlower); + return ath; + } + + function compute_ath(gfp) { + var ATH_l = gfp.internal_flags.ATH.l; + var ATH_psfb21 = gfp.internal_flags.ATH.psfb21; + var ATH_s = gfp.internal_flags.ATH.s; + var ATH_psfb12 = gfp.internal_flags.ATH.psfb12; + var gfc = gfp.internal_flags; + var samp_freq = gfp.out_samplerate; + + for (var sfb = 0; sfb < Encoder.SBMAX_l; sfb++) { + var start = gfc.scalefac_band.l[sfb]; + var end = gfc.scalefac_band.l[sfb + 1]; + ATH_l[sfb] = Float.MAX_VALUE; + for (var i = start; i < end; i++) { + var freq = i * samp_freq / (2 * 576); + var ATH_f = ATHmdct(gfp, freq); + /* freq in kHz */ + ATH_l[sfb] = Math.min(ATH_l[sfb], ATH_f); + } + } + + for (var sfb = 0; sfb < Encoder.PSFB21; sfb++) { + var start = gfc.scalefac_band.psfb21[sfb]; + var end = gfc.scalefac_band.psfb21[sfb + 1]; + ATH_psfb21[sfb] = Float.MAX_VALUE; + for (var i = start; i < end; i++) { + var freq = i * samp_freq / (2 * 576); + var ATH_f = ATHmdct(gfp, freq); + /* freq in kHz */ + ATH_psfb21[sfb] = Math.min(ATH_psfb21[sfb], ATH_f); + } + } + + for (var sfb = 0; sfb < Encoder.SBMAX_s; sfb++) { + var start = gfc.scalefac_band.s[sfb]; + var end = gfc.scalefac_band.s[sfb + 1]; + ATH_s[sfb] = Float.MAX_VALUE; + for (var i = start; i < end; i++) { + var freq = i * samp_freq / (2 * 192); + var ATH_f = ATHmdct(gfp, freq); + /* freq in kHz */ + ATH_s[sfb] = Math.min(ATH_s[sfb], ATH_f); + } + ATH_s[sfb] *= (gfc.scalefac_band.s[sfb + 1] - gfc.scalefac_band.s[sfb]); + } + + for (var sfb = 0; sfb < Encoder.PSFB12; sfb++) { + var start = gfc.scalefac_band.psfb12[sfb]; + var end = gfc.scalefac_band.psfb12[sfb + 1]; + ATH_psfb12[sfb] = Float.MAX_VALUE; + for (var i = start; i < end; i++) { + var freq = i * samp_freq / (2 * 192); + var ATH_f = ATHmdct(gfp, freq); + /* freq in kHz */ + ATH_psfb12[sfb] = Math.min(ATH_psfb12[sfb], ATH_f); + } + /* not sure about the following */ + ATH_psfb12[sfb] *= (gfc.scalefac_band.s[13] - gfc.scalefac_band.s[12]); + } + + /* + * no-ATH mode: reduce ATH to -200 dB + */ + if (gfp.noATH) { + for (var sfb = 0; sfb < Encoder.SBMAX_l; sfb++) { + ATH_l[sfb] = 1E-20; + } + for (var sfb = 0; sfb < Encoder.PSFB21; sfb++) { + ATH_psfb21[sfb] = 1E-20; + } + for (var sfb = 0; sfb < Encoder.SBMAX_s; sfb++) { + ATH_s[sfb] = 1E-20; + } + for (var sfb = 0; sfb < Encoder.PSFB12; sfb++) { + ATH_psfb12[sfb] = 1E-20; + } + } + + /* + * work in progress, don't rely on it too much + */ + gfc.ATH.floor = 10. * Math.log10(ATHmdct(gfp, -1.)); + } + + /** + * initialization for iteration_loop + */ + this.iteration_init = function (gfp) { + var gfc = gfp.internal_flags; + var l3_side = gfc.l3_side; + var i; + + if (gfc.iteration_init_init == 0) { + gfc.iteration_init_init = 1; + + l3_side.main_data_begin = 0; + compute_ath(gfp); + + pow43[0] = 0.0; + for (i = 1; i < PRECALC_SIZE; i++) + pow43[i] = Math.pow(i, 4.0 / 3.0); + + for (i = 0; i < PRECALC_SIZE - 1; i++) + adj43[i] = ((i + 1) - Math.pow( + 0.5 * (pow43[i] + pow43[i + 1]), 0.75)); + adj43[i] = 0.5; + + for (i = 0; i < Q_MAX; i++) + ipow20[i] = Math.pow(2.0, (i - 210) * -0.1875); + for (i = 0; i <= Q_MAX + Q_MAX2; i++) + pow20[i] = Math.pow(2.0, (i - 210 - Q_MAX2) * 0.25); + + tak.huffman_init(gfc); + + { + var bass, alto, treble, sfb21; + + i = (gfp.exp_nspsytune >> 2) & 63; + if (i >= 32) + i -= 64; + bass = Math.pow(10, i / 4.0 / 10.0); + + i = (gfp.exp_nspsytune >> 8) & 63; + if (i >= 32) + i -= 64; + alto = Math.pow(10, i / 4.0 / 10.0); + + i = (gfp.exp_nspsytune >> 14) & 63; + if (i >= 32) + i -= 64; + treble = Math.pow(10, i / 4.0 / 10.0); + + /* + * to be compatible with Naoki's original code, the next 6 bits + * define only the amount of changing treble for sfb21 + */ + i = (gfp.exp_nspsytune >> 20) & 63; + if (i >= 32) + i -= 64; + sfb21 = treble * Math.pow(10, i / 4.0 / 10.0); + for (i = 0; i < Encoder.SBMAX_l; i++) { + var f; + if (i <= 6) + f = bass; + else if (i <= 13) + f = alto; + else if (i <= 20) + f = treble; + else + f = sfb21; + + gfc.nsPsy.longfact[i] = f; + } + for (i = 0; i < Encoder.SBMAX_s; i++) { + var f; + if (i <= 5) + f = bass; + else if (i <= 10) + f = alto; + else if (i <= 11) + f = treble; + else + f = sfb21; + + gfc.nsPsy.shortfact[i] = f; + } + } + } + } + + /** + * allocate bits among 2 channels based on PE
+ * mt 6/99
+ * bugfixes rh 8/01: often allocated more than the allowed 4095 bits + */ + this.on_pe = function (gfp, pe, + targ_bits, mean_bits, gr, cbr) { + var gfc = gfp.internal_flags; + var tbits = 0, bits; + var add_bits = new_int(2); + var ch; + + /* allocate targ_bits for granule */ + var mb = new MeanBits(tbits); + var extra_bits = rv.ResvMaxBits(gfp, mean_bits, mb, cbr); + tbits = mb.bits; + /* maximum allowed bits for this granule */ + var max_bits = tbits + extra_bits; + if (max_bits > LameInternalFlags.MAX_BITS_PER_GRANULE) { + // hard limit per granule + max_bits = LameInternalFlags.MAX_BITS_PER_GRANULE; + } + for (bits = 0, ch = 0; ch < gfc.channels_out; ++ch) { + /****************************************************************** + * allocate bits for each channel + ******************************************************************/ + targ_bits[ch] = Math.min(LameInternalFlags.MAX_BITS_PER_CHANNEL, + tbits / gfc.channels_out); + + add_bits[ch] = 0 | (targ_bits[ch] * pe[gr][ch] / 700.0 - targ_bits[ch]); + + /* at most increase bits by 1.5*average */ + if (add_bits[ch] > mean_bits * 3 / 4) + add_bits[ch] = mean_bits * 3 / 4; + if (add_bits[ch] < 0) + add_bits[ch] = 0; + + if (add_bits[ch] + targ_bits[ch] > LameInternalFlags.MAX_BITS_PER_CHANNEL) + add_bits[ch] = Math.max(0, + LameInternalFlags.MAX_BITS_PER_CHANNEL - targ_bits[ch]); + + bits += add_bits[ch]; + } + if (bits > extra_bits) { + for (ch = 0; ch < gfc.channels_out; ++ch) { + add_bits[ch] = extra_bits * add_bits[ch] / bits; + } + } + + for (ch = 0; ch < gfc.channels_out; ++ch) { + targ_bits[ch] += add_bits[ch]; + extra_bits -= add_bits[ch]; + } + + for (bits = 0, ch = 0; ch < gfc.channels_out; ++ch) { + bits += targ_bits[ch]; + } + if (bits > LameInternalFlags.MAX_BITS_PER_GRANULE) { + var sum = 0; + for (ch = 0; ch < gfc.channels_out; ++ch) { + targ_bits[ch] *= LameInternalFlags.MAX_BITS_PER_GRANULE; + targ_bits[ch] /= bits; + sum += targ_bits[ch]; + } + } + + return max_bits; + } + + this.reduce_side = function (targ_bits, ms_ener_ratio, mean_bits, max_bits) { + + /* + * ms_ener_ratio = 0: allocate 66/33 mid/side fac=.33 ms_ener_ratio =.5: + * allocate 50/50 mid/side fac= 0 + */ + /* 75/25 split is fac=.5 */ + var fac = .33 * (.5 - ms_ener_ratio) / .5; + if (fac < 0) + fac = 0; + if (fac > .5) + fac = .5; + + /* number of bits to move from side channel to mid channel */ + /* move_bits = fac*targ_bits[1]; */ + var move_bits = 0 | (fac * .5 * (targ_bits[0] + targ_bits[1])); + + if (move_bits > LameInternalFlags.MAX_BITS_PER_CHANNEL - targ_bits[0]) { + move_bits = LameInternalFlags.MAX_BITS_PER_CHANNEL - targ_bits[0]; + } + if (move_bits < 0) + move_bits = 0; + + if (targ_bits[1] >= 125) { + /* dont reduce side channel below 125 bits */ + if (targ_bits[1] - move_bits > 125) { + + /* if mid channel already has 2x more than average, dont bother */ + /* mean_bits = bits per granule (for both channels) */ + if (targ_bits[0] < mean_bits) + targ_bits[0] += move_bits; + targ_bits[1] -= move_bits; + } else { + targ_bits[0] += targ_bits[1] - 125; + targ_bits[1] = 125; + } + } + + move_bits = targ_bits[0] + targ_bits[1]; + if (move_bits > max_bits) { + targ_bits[0] = (max_bits * targ_bits[0]) / move_bits; + targ_bits[1] = (max_bits * targ_bits[1]) / move_bits; + } + }; + + /** + * Robert Hegemann 2001-04-27: + * this adjusts the ATH, keeping the original noise floor + * affects the higher frequencies more than the lower ones + */ + this.athAdjust = function (a, x, athFloor) { + /* + * work in progress + */ + var o = 90.30873362; + var p = 94.82444863; + var u = Util.FAST_LOG10_X(x, 10.0); + var v = a * a; + var w = 0.0; + u -= athFloor; + /* undo scaling */ + if (v > 1E-20) + w = 1. + Util.FAST_LOG10_X(v, 10.0 / o); + if (w < 0) + w = 0.; + u *= w; + u += athFloor + o - p; + /* redo scaling */ + + return Math.pow(10., 0.1 * u); + }; + + /** + * Calculate the allowed distortion for each scalefactor band, as determined + * by the psychoacoustic model. xmin(sb) = ratio(sb) * en(sb) / bw(sb) + * + * returns number of sfb's with energy > ATH + */ + this.calc_xmin = function (gfp, ratio, cod_info, pxmin) { + var pxminPos = 0; + var gfc = gfp.internal_flags; + var gsfb, j = 0, ath_over = 0; + var ATH = gfc.ATH; + var xr = cod_info.xr; + var enable_athaa_fix = (gfp.VBR == VbrMode.vbr_mtrh) ? 1 : 0; + var masking_lower = gfc.masking_lower; + + if (gfp.VBR == VbrMode.vbr_mtrh || gfp.VBR == VbrMode.vbr_mt) { + /* was already done in PSY-Model */ + masking_lower = 1.0; + } + + for (gsfb = 0; gsfb < cod_info.psy_lmax; gsfb++) { + var en0, xmin; + var rh1, rh2; + var width, l; + + if (gfp.VBR == VbrMode.vbr_rh || gfp.VBR == VbrMode.vbr_mtrh) + xmin = athAdjust(ATH.adjust, ATH.l[gsfb], ATH.floor); + else + xmin = ATH.adjust * ATH.l[gsfb]; + + width = cod_info.width[gsfb]; + rh1 = xmin / width; + rh2 = DBL_EPSILON; + l = width >> 1; + en0 = 0.0; + do { + var xa, xb; + xa = xr[j] * xr[j]; + en0 += xa; + rh2 += (xa < rh1) ? xa : rh1; + j++; + xb = xr[j] * xr[j]; + en0 += xb; + rh2 += (xb < rh1) ? xb : rh1; + j++; + } while (--l > 0); + if (en0 > xmin) + ath_over++; + + if (gsfb == Encoder.SBPSY_l) { + var x = xmin * gfc.nsPsy.longfact[gsfb]; + if (rh2 < x) { + rh2 = x; + } + } + if (enable_athaa_fix != 0) { + xmin = rh2; + } + if (!gfp.ATHonly) { + var e = ratio.en.l[gsfb]; + if (e > 0.0) { + var x; + x = en0 * ratio.thm.l[gsfb] * masking_lower / e; + if (enable_athaa_fix != 0) + x *= gfc.nsPsy.longfact[gsfb]; + if (xmin < x) + xmin = x; + } + } + if (enable_athaa_fix != 0) + pxmin[pxminPos++] = xmin; + else + pxmin[pxminPos++] = xmin * gfc.nsPsy.longfact[gsfb]; + } + /* end of long block loop */ + + /* use this function to determine the highest non-zero coeff */ + var max_nonzero = 575; + if (cod_info.block_type != Encoder.SHORT_TYPE) { + // NORM, START or STOP type, but not SHORT + var k = 576; + while (k-- != 0 && BitStream.EQ(xr[k], 0)) { + max_nonzero = k; + } + } + cod_info.max_nonzero_coeff = max_nonzero; + + for (var sfb = cod_info.sfb_smin; gsfb < cod_info.psymax; sfb++, gsfb += 3) { + var width, b; + var tmpATH; + if (gfp.VBR == VbrMode.vbr_rh || gfp.VBR == VbrMode.vbr_mtrh) + tmpATH = athAdjust(ATH.adjust, ATH.s[sfb], ATH.floor); + else + tmpATH = ATH.adjust * ATH.s[sfb]; + + width = cod_info.width[gsfb]; + for (b = 0; b < 3; b++) { + var en0 = 0.0, xmin; + var rh1, rh2; + var l = width >> 1; + + rh1 = tmpATH / width; + rh2 = DBL_EPSILON; + do { + var xa, xb; + xa = xr[j] * xr[j]; + en0 += xa; + rh2 += (xa < rh1) ? xa : rh1; + j++; + xb = xr[j] * xr[j]; + en0 += xb; + rh2 += (xb < rh1) ? xb : rh1; + j++; + } while (--l > 0); + if (en0 > tmpATH) + ath_over++; + if (sfb == Encoder.SBPSY_s) { + var x = tmpATH * gfc.nsPsy.shortfact[sfb]; + if (rh2 < x) { + rh2 = x; + } + } + if (enable_athaa_fix != 0) + xmin = rh2; + else + xmin = tmpATH; + + if (!gfp.ATHonly && !gfp.ATHshort) { + var e = ratio.en.s[sfb][b]; + if (e > 0.0) { + var x; + x = en0 * ratio.thm.s[sfb][b] * masking_lower / e; + if (enable_athaa_fix != 0) + x *= gfc.nsPsy.shortfact[sfb]; + if (xmin < x) + xmin = x; + } + } + if (enable_athaa_fix != 0) + pxmin[pxminPos++] = xmin; + else + pxmin[pxminPos++] = xmin * gfc.nsPsy.shortfact[sfb]; + } + /* b */ + if (gfp.useTemporal) { + if (pxmin[pxminPos - 3] > pxmin[pxminPos - 3 + 1]) + pxmin[pxminPos - 3 + 1] += (pxmin[pxminPos - 3] - pxmin[pxminPos - 3 + 1]) + * gfc.decay; + if (pxmin[pxminPos - 3 + 1] > pxmin[pxminPos - 3 + 2]) + pxmin[pxminPos - 3 + 2] += (pxmin[pxminPos - 3 + 1] - pxmin[pxminPos - 3 + 2]) + * gfc.decay; + } + } + /* end of short block sfb loop */ + + return ath_over; + }; + + function StartLine(j) { + this.s = j; + } + + this.calc_noise_core = function (cod_info, startline, l, step) { + var noise = 0; + var j = startline.s; + var ix = cod_info.l3_enc; + + if (j > cod_info.count1) { + while ((l--) != 0) { + var temp; + temp = cod_info.xr[j]; + j++; + noise += temp * temp; + temp = cod_info.xr[j]; + j++; + noise += temp * temp; + } + } else if (j > cod_info.big_values) { + var ix01 = new_float(2); + ix01[0] = 0; + ix01[1] = step; + while ((l--) != 0) { + var temp; + temp = Math.abs(cod_info.xr[j]) - ix01[ix[j]]; + j++; + noise += temp * temp; + temp = Math.abs(cod_info.xr[j]) - ix01[ix[j]]; + j++; + noise += temp * temp; + } + } else { + while ((l--) != 0) { + var temp; + temp = Math.abs(cod_info.xr[j]) - pow43[ix[j]] * step; + j++; + noise += temp * temp; + temp = Math.abs(cod_info.xr[j]) - pow43[ix[j]] * step; + j++; + noise += temp * temp; + } + } + + startline.s = j; + return noise; + } + + /** + *
+     * -oo dB  =>  -1.00
+     * - 6 dB  =>  -0.97
+     * - 3 dB  =>  -0.80
+     * - 2 dB  =>  -0.64
+     * - 1 dB  =>  -0.38
+     *   0 dB  =>   0.00
+     * + 1 dB  =>  +0.49
+     * + 2 dB  =>  +1.06
+     * + 3 dB  =>  +1.68
+     * + 6 dB  =>  +3.69
+     * +10 dB  =>  +6.45
+     * 
+ */ + this.calc_noise = function (cod_info, l3_xmin, distort, res, prev_noise) { + var distortPos = 0; + var l3_xminPos = 0; + var sfb, l, over = 0; + var over_noise_db = 0; + /* 0 dB relative to masking */ + var tot_noise_db = 0; + /* -200 dB relative to masking */ + var max_noise = -20.0; + var j = 0; + var scalefac = cod_info.scalefac; + var scalefacPos = 0; + + res.over_SSD = 0; + + for (sfb = 0; sfb < cod_info.psymax; sfb++) { + var s = cod_info.global_gain + - (((scalefac[scalefacPos++]) + (cod_info.preflag != 0 ? pretab[sfb] + : 0)) << (cod_info.scalefac_scale + 1)) + - cod_info.subblock_gain[cod_info.window[sfb]] * 8; + var noise = 0.0; + + if (prev_noise != null && (prev_noise.step[sfb] == s)) { + + /* use previously computed values */ + noise = prev_noise.noise[sfb]; + j += cod_info.width[sfb]; + distort[distortPos++] = noise / l3_xmin[l3_xminPos++]; + + noise = prev_noise.noise_log[sfb]; + + } else { + var step = POW20(s); + l = cod_info.width[sfb] >> 1; + + if ((j + cod_info.width[sfb]) > cod_info.max_nonzero_coeff) { + var usefullsize; + usefullsize = cod_info.max_nonzero_coeff - j + 1; + + if (usefullsize > 0) + l = usefullsize >> 1; + else + l = 0; + } + + var sl = new StartLine(j); + noise = this.calc_noise_core(cod_info, sl, l, step); + j = sl.s; + + if (prev_noise != null) { + /* save noise values */ + prev_noise.step[sfb] = s; + prev_noise.noise[sfb] = noise; + } + + noise = distort[distortPos++] = noise / l3_xmin[l3_xminPos++]; + + /* multiplying here is adding in dB, but can overflow */ + noise = Util.FAST_LOG10(Math.max(noise, 1E-20)); + + if (prev_noise != null) { + /* save noise values */ + prev_noise.noise_log[sfb] = noise; + } + } + + if (prev_noise != null) { + /* save noise values */ + prev_noise.global_gain = cod_info.global_gain; + } + + tot_noise_db += noise; + + if (noise > 0.0) { + var tmp; + + tmp = Math.max(0 | (noise * 10 + .5), 1); + res.over_SSD += tmp * tmp; + + over++; + /* multiplying here is adding in dB -but can overflow */ + /* over_noise *= noise; */ + over_noise_db += noise; + } + max_noise = Math.max(max_noise, noise); + + } + + res.over_count = over; + res.tot_noise = tot_noise_db; + res.over_noise = over_noise_db; + res.max_noise = max_noise; + + return over; + } + + /** + * updates plotting data + * + * Mark Taylor 2000-??-?? + * + * Robert Hegemann: moved noise/distortion calc into it + */ + this.set_pinfo = function (gfp, cod_info, ratio, gr, ch) { + var gfc = gfp.internal_flags; + var sfb, sfb2; + var l; + var en0, en1; + var ifqstep = (cod_info.scalefac_scale == 0) ? .5 : 1.0; + var scalefac = cod_info.scalefac; + + var l3_xmin = new_float(L3Side.SFBMAX); + var xfsf = new_float(L3Side.SFBMAX); + var noise = new CalcNoiseResult(); + + calc_xmin(gfp, ratio, cod_info, l3_xmin); + calc_noise(cod_info, l3_xmin, xfsf, noise, null); + + var j = 0; + sfb2 = cod_info.sfb_lmax; + if (cod_info.block_type != Encoder.SHORT_TYPE + && 0 == cod_info.mixed_block_flag) + sfb2 = 22; + for (sfb = 0; sfb < sfb2; sfb++) { + var start = gfc.scalefac_band.l[sfb]; + var end = gfc.scalefac_band.l[sfb + 1]; + var bw = end - start; + for (en0 = 0.0; j < end; j++) + en0 += cod_info.xr[j] * cod_info.xr[j]; + en0 /= bw; + /* convert to MDCT units */ + /* scaling so it shows up on FFT plot */ + en1 = 1e15; + gfc.pinfo.en[gr][ch][sfb] = en1 * en0; + gfc.pinfo.xfsf[gr][ch][sfb] = en1 * l3_xmin[sfb] * xfsf[sfb] / bw; + + if (ratio.en.l[sfb] > 0 && !gfp.ATHonly) + en0 = en0 / ratio.en.l[sfb]; + else + en0 = 0.0; + + gfc.pinfo.thr[gr][ch][sfb] = en1 + * Math.max(en0 * ratio.thm.l[sfb], gfc.ATH.l[sfb]); + + /* there is no scalefactor bands >= SBPSY_l */ + gfc.pinfo.LAMEsfb[gr][ch][sfb] = 0; + if (cod_info.preflag != 0 && sfb >= 11) + gfc.pinfo.LAMEsfb[gr][ch][sfb] = -ifqstep * pretab[sfb]; + + if (sfb < Encoder.SBPSY_l) { + /* scfsi should be decoded by caller side */ + gfc.pinfo.LAMEsfb[gr][ch][sfb] -= ifqstep * scalefac[sfb]; + } + } + /* for sfb */ + + if (cod_info.block_type == Encoder.SHORT_TYPE) { + sfb2 = sfb; + for (sfb = cod_info.sfb_smin; sfb < Encoder.SBMAX_s; sfb++) { + var start = gfc.scalefac_band.s[sfb]; + var end = gfc.scalefac_band.s[sfb + 1]; + var bw = end - start; + for (var i = 0; i < 3; i++) { + for (en0 = 0.0, l = start; l < end; l++) { + en0 += cod_info.xr[j] * cod_info.xr[j]; + j++; + } + en0 = Math.max(en0 / bw, 1e-20); + /* convert to MDCT units */ + /* scaling so it shows up on FFT plot */ + en1 = 1e15; + + gfc.pinfo.en_s[gr][ch][3 * sfb + i] = en1 * en0; + gfc.pinfo.xfsf_s[gr][ch][3 * sfb + i] = en1 * l3_xmin[sfb2] + * xfsf[sfb2] / bw; + if (ratio.en.s[sfb][i] > 0) + en0 = en0 / ratio.en.s[sfb][i]; + else + en0 = 0.0; + if (gfp.ATHonly || gfp.ATHshort) + en0 = 0; + + gfc.pinfo.thr_s[gr][ch][3 * sfb + i] = en1 + * Math.max(en0 * ratio.thm.s[sfb][i], + gfc.ATH.s[sfb]); + + /* there is no scalefactor bands >= SBPSY_s */ + gfc.pinfo.LAMEsfb_s[gr][ch][3 * sfb + i] = -2.0 + * cod_info.subblock_gain[i]; + if (sfb < Encoder.SBPSY_s) { + gfc.pinfo.LAMEsfb_s[gr][ch][3 * sfb + i] -= ifqstep + * scalefac[sfb2]; + } + sfb2++; + } + } + } + /* block type short */ + gfc.pinfo.LAMEqss[gr][ch] = cod_info.global_gain; + gfc.pinfo.LAMEmainbits[gr][ch] = cod_info.part2_3_length + + cod_info.part2_length; + gfc.pinfo.LAMEsfbits[gr][ch] = cod_info.part2_length; + + gfc.pinfo.over[gr][ch] = noise.over_count; + gfc.pinfo.max_noise[gr][ch] = noise.max_noise * 10.0; + gfc.pinfo.over_noise[gr][ch] = noise.over_noise * 10.0; + gfc.pinfo.tot_noise[gr][ch] = noise.tot_noise * 10.0; + gfc.pinfo.over_SSD[gr][ch] = noise.over_SSD; + } + + /** + * updates plotting data for a whole frame + * + * Robert Hegemann 2000-10-21 + */ + function set_frame_pinfo(gfp, ratio) { + var gfc = gfp.internal_flags; + + gfc.masking_lower = 1.0; + + /* + * for every granule and channel patch l3_enc and set info + */ + for (var gr = 0; gr < gfc.mode_gr; gr++) { + for (var ch = 0; ch < gfc.channels_out; ch++) { + var cod_info = gfc.l3_side.tt[gr][ch]; + var scalefac_sav = new_int(L3Side.SFBMAX); + System.arraycopy(cod_info.scalefac, 0, scalefac_sav, 0, + scalefac_sav.length); + + /* + * reconstruct the scalefactors in case SCFSI was used + */ + if (gr == 1) { + var sfb; + for (sfb = 0; sfb < cod_info.sfb_lmax; sfb++) { + if (cod_info.scalefac[sfb] < 0) /* scfsi */ + cod_info.scalefac[sfb] = gfc.l3_side.tt[0][ch].scalefac[sfb]; + } + } + + set_pinfo(gfp, cod_info, ratio[gr][ch], gr, ch); + System.arraycopy(scalefac_sav, 0, cod_info.scalefac, 0, + scalefac_sav.length); + } + /* for ch */ + } + /* for gr */ + } + +} + + +function CalcNoiseData() { + this.global_gain = 0; + this.sfb_count1 = 0; + this.step = new_int(39); + this.noise = new_float(39); + this.noise_log = new_float(39); +} + +//package mp3; + + +function GrInfo() { + //float xr[] = new float[576]; + this.xr = new_float(576); + //int l3_enc[] = new int[576]; + this.l3_enc = new_int(576); + //int scalefac[] = new int[L3Side.SFBMAX]; + this.scalefac = new_int(L3Side.SFBMAX); + this.xrpow_max = 0.; + + this.part2_3_length = 0; + this.big_values = 0; + this.count1 = 0; + this.global_gain = 0; + this.scalefac_compress = 0; + this.block_type = 0; + this.mixed_block_flag = 0; + this.table_select = new_int(3); + this.subblock_gain = new_int(3 + 1); + this.region0_count = 0; + this.region1_count = 0; + this.preflag = 0; + this.scalefac_scale = 0; + this.count1table_select = 0; + + this.part2_length = 0; + this.sfb_lmax = 0; + this.sfb_smin = 0; + this.psy_lmax = 0; + this.sfbmax = 0; + this.psymax = 0; + this.sfbdivide = 0; + this.width = new_int(L3Side.SFBMAX); + this.window = new_int(L3Side.SFBMAX); + this.count1bits = 0; + /** + * added for LSF + */ + this.sfb_partition_table = null; + this.slen = new_int(4); + + this.max_nonzero_coeff = 0; + + var self = this; + function clone_int(array) { + return new Int32Array(array); + } + function clone_float(array) { + return new Float32Array(array); + } + this.assign = function (other) { + self.xr = clone_float(other.xr); //.slice(0); //clone(); + self.l3_enc = clone_int(other.l3_enc); //.slice(0); //clone(); + self.scalefac = clone_int(other.scalefac);//.slice(0); //clone(); + self.xrpow_max = other.xrpow_max; + + self.part2_3_length = other.part2_3_length; + self.big_values = other.big_values; + self.count1 = other.count1; + self.global_gain = other.global_gain; + self.scalefac_compress = other.scalefac_compress; + self.block_type = other.block_type; + self.mixed_block_flag = other.mixed_block_flag; + self.table_select = clone_int(other.table_select);//.slice(0); //clone(); + self.subblock_gain = clone_int(other.subblock_gain); //.slice(0); //.clone(); + self.region0_count = other.region0_count; + self.region1_count = other.region1_count; + self.preflag = other.preflag; + self.scalefac_scale = other.scalefac_scale; + self.count1table_select = other.count1table_select; + + self.part2_length = other.part2_length; + self.sfb_lmax = other.sfb_lmax; + self.sfb_smin = other.sfb_smin; + self.psy_lmax = other.psy_lmax; + self.sfbmax = other.sfbmax; + self.psymax = other.psymax; + self.sfbdivide = other.sfbdivide; + self.width = clone_int(other.width); //.slice(0); //.clone(); + self.window = clone_int(other.window); //.slice(0); //.clone(); + self.count1bits = other.count1bits; + + self.sfb_partition_table = other.sfb_partition_table.slice(0); //.clone(); + self.slen = clone_int(other.slen); //.slice(0); //.clone(); + self.max_nonzero_coeff = other.max_nonzero_coeff; + } +} + + +var L3Side = {}; + + + /** + * max scalefactor band, max(SBMAX_l, SBMAX_s*3, (SBMAX_s-3)*3+8) + */ +L3Side.SFBMAX = (Encoder.SBMAX_s * 3); + +/* + * MP3 quantization + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 1999-2003 Takehiro Tominaga + * Copyright (c) 2000-2007 Robert Hegemann + * Copyright (c) 2001-2005 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: Quantize.java,v 1.24 2011/05/24 20:48:06 kenchis Exp $ */ + +//package mp3; + +//import java.util.Arrays; + + +function Quantize() { + var bs; + this.rv = null; + var rv; + this.qupvt = null; + var qupvt; + + var vbr = new VBRQuantize(); + var tk; + + this.setModules = function (_bs, _rv, _qupvt, _tk) { + bs = _bs; + rv = _rv; + this.rv = _rv; + qupvt = _qupvt; + this.qupvt = _qupvt; + tk = _tk; + vbr.setModules(qupvt, tk); + } + + /** + * convert from L/R <. Mid/Side + */ + this.ms_convert = function (l3_side, gr) { + for (var i = 0; i < 576; ++i) { + var l = l3_side.tt[gr][0].xr[i]; + var r = l3_side.tt[gr][1].xr[i]; + l3_side.tt[gr][0].xr[i] = (l + r) * (Util.SQRT2 * 0.5); + l3_side.tt[gr][1].xr[i] = (l - r) * (Util.SQRT2 * 0.5); + } + }; + + /** + * mt 6/99 + * + * initializes cod_info, scalefac and xrpow + * + * returns 0 if all energies in xr are zero, else 1 + */ + function init_xrpow_core(cod_info, xrpow, upper, sum) { + sum = 0; + for (var i = 0; i <= upper; ++i) { + var tmp = Math.abs(cod_info.xr[i]); + sum += tmp; + xrpow[i] = Math.sqrt(tmp * Math.sqrt(tmp)); + + if (xrpow[i] > cod_info.xrpow_max) + cod_info.xrpow_max = xrpow[i]; + } + return sum; + } + + this.init_xrpow = function (gfc, cod_info, xrpow) { + var sum = 0; + var upper = 0 | cod_info.max_nonzero_coeff; + + cod_info.xrpow_max = 0; + + /* + * check if there is some energy we have to quantize and calculate xrpow + * matching our fresh scalefactors + */ + + Arrays.fill(xrpow, upper, 576, 0); + + sum = init_xrpow_core(cod_info, xrpow, upper, sum); + + /* + * return 1 if we have something to quantize, else 0 + */ + if (sum > 1E-20) { + var j = 0; + if ((gfc.substep_shaping & 2) != 0) + j = 1; + + for (var i = 0; i < cod_info.psymax; i++) + gfc.pseudohalf[i] = j; + + return true; + } + + Arrays.fill(cod_info.l3_enc, 0, 576, 0); + return false; + } + + /** + * Gabriel Bouvigne feb/apr 2003
+ * Analog silence detection in partitionned sfb21 or sfb12 for short blocks + * + * From top to bottom of sfb, changes to 0 coeffs which are below ath. It + * stops on the first coeff higher than ath. + */ + function psfb21_analogsilence(gfc, cod_info) { + var ath = gfc.ATH; + var xr = cod_info.xr; + + if (cod_info.block_type != Encoder.SHORT_TYPE) { + /* NORM, START or STOP type, but not SHORT blocks */ + var stop = false; + for (var gsfb = Encoder.PSFB21 - 1; gsfb >= 0 && !stop; gsfb--) { + var start = gfc.scalefac_band.psfb21[gsfb]; + var end = gfc.scalefac_band.psfb21[gsfb + 1]; + var ath21 = qupvt.athAdjust(ath.adjust, ath.psfb21[gsfb], + ath.floor); + + if (gfc.nsPsy.longfact[21] > 1e-12) + ath21 *= gfc.nsPsy.longfact[21]; + + for (var j = end - 1; j >= start; j--) { + if (Math.abs(xr[j]) < ath21) + xr[j] = 0; + else { + stop = true; + break; + } + } + } + } else { + /* note: short blocks coeffs are reordered */ + for (var block = 0; block < 3; block++) { + var stop = false; + for (var gsfb = Encoder.PSFB12 - 1; gsfb >= 0 && !stop; gsfb--) { + var start = gfc.scalefac_band.s[12] + * 3 + + (gfc.scalefac_band.s[13] - gfc.scalefac_band.s[12]) + * block + + (gfc.scalefac_band.psfb12[gsfb] - gfc.scalefac_band.psfb12[0]); + var end = start + + (gfc.scalefac_band.psfb12[gsfb + 1] - gfc.scalefac_band.psfb12[gsfb]); + var ath12 = qupvt.athAdjust(ath.adjust, ath.psfb12[gsfb], + ath.floor); + + if (gfc.nsPsy.shortfact[12] > 1e-12) + ath12 *= gfc.nsPsy.shortfact[12]; + + for (var j = end - 1; j >= start; j--) { + if (Math.abs(xr[j]) < ath12) + xr[j] = 0; + else { + stop = true; + break; + } + } + } + } + } + + } + + this.init_outer_loop = function (gfc, cod_info) { + /* + * initialize fresh cod_info + */ + cod_info.part2_3_length = 0; + cod_info.big_values = 0; + cod_info.count1 = 0; + cod_info.global_gain = 210; + cod_info.scalefac_compress = 0; + /* mixed_block_flag, block_type was set in psymodel.c */ + cod_info.table_select[0] = 0; + cod_info.table_select[1] = 0; + cod_info.table_select[2] = 0; + cod_info.subblock_gain[0] = 0; + cod_info.subblock_gain[1] = 0; + cod_info.subblock_gain[2] = 0; + cod_info.subblock_gain[3] = 0; + /* this one is always 0 */ + cod_info.region0_count = 0; + cod_info.region1_count = 0; + cod_info.preflag = 0; + cod_info.scalefac_scale = 0; + cod_info.count1table_select = 0; + cod_info.part2_length = 0; + cod_info.sfb_lmax = Encoder.SBPSY_l; + cod_info.sfb_smin = Encoder.SBPSY_s; + cod_info.psy_lmax = gfc.sfb21_extra ? Encoder.SBMAX_l : Encoder.SBPSY_l; + cod_info.psymax = cod_info.psy_lmax; + cod_info.sfbmax = cod_info.sfb_lmax; + cod_info.sfbdivide = 11; + for (var sfb = 0; sfb < Encoder.SBMAX_l; sfb++) { + cod_info.width[sfb] = gfc.scalefac_band.l[sfb + 1] + - gfc.scalefac_band.l[sfb]; + /* which is always 0. */ + cod_info.window[sfb] = 3; + } + if (cod_info.block_type == Encoder.SHORT_TYPE) { + var ixwork = new_float(576); + + cod_info.sfb_smin = 0; + cod_info.sfb_lmax = 0; + if (cod_info.mixed_block_flag != 0) { + /* + * MPEG-1: sfbs 0-7 long block, 3-12 short blocks MPEG-2(.5): + * sfbs 0-5 long block, 3-12 short blocks + */ + cod_info.sfb_smin = 3; + cod_info.sfb_lmax = gfc.mode_gr * 2 + 4; + } + cod_info.psymax = cod_info.sfb_lmax + + 3 + * ((gfc.sfb21_extra ? Encoder.SBMAX_s : Encoder.SBPSY_s) - cod_info.sfb_smin); + cod_info.sfbmax = cod_info.sfb_lmax + 3 + * (Encoder.SBPSY_s - cod_info.sfb_smin); + cod_info.sfbdivide = cod_info.sfbmax - 18; + cod_info.psy_lmax = cod_info.sfb_lmax; + /* re-order the short blocks, for more efficient encoding below */ + /* By Takehiro TOMINAGA */ + /* + * Within each scalefactor band, data is given for successive time + * windows, beginning with window 0 and ending with window 2. Within + * each window, the quantized values are then arranged in order of + * increasing frequency... + */ + var ix = gfc.scalefac_band.l[cod_info.sfb_lmax]; + System.arraycopy(cod_info.xr, 0, ixwork, 0, 576); + for (var sfb = cod_info.sfb_smin; sfb < Encoder.SBMAX_s; sfb++) { + var start = gfc.scalefac_band.s[sfb]; + var end = gfc.scalefac_band.s[sfb + 1]; + for (var window = 0; window < 3; window++) { + for (var l = start; l < end; l++) { + cod_info.xr[ix++] = ixwork[3 * l + window]; + } + } + } + + var j = cod_info.sfb_lmax; + for (var sfb = cod_info.sfb_smin; sfb < Encoder.SBMAX_s; sfb++) { + cod_info.width[j] = cod_info.width[j + 1] = cod_info.width[j + 2] = gfc.scalefac_band.s[sfb + 1] + - gfc.scalefac_band.s[sfb]; + cod_info.window[j] = 0; + cod_info.window[j + 1] = 1; + cod_info.window[j + 2] = 2; + j += 3; + } + } + + cod_info.count1bits = 0; + cod_info.sfb_partition_table = qupvt.nr_of_sfb_block[0][0]; + cod_info.slen[0] = 0; + cod_info.slen[1] = 0; + cod_info.slen[2] = 0; + cod_info.slen[3] = 0; + + cod_info.max_nonzero_coeff = 575; + + /* + * fresh scalefactors are all zero + */ + Arrays.fill(cod_info.scalefac, 0); + + psfb21_analogsilence(gfc, cod_info); + }; + + function BinSearchDirection(ordinal) { + this.ordinal = ordinal; + } + + BinSearchDirection.BINSEARCH_NONE = new BinSearchDirection(0); + BinSearchDirection.BINSEARCH_UP = new BinSearchDirection(1); + BinSearchDirection.BINSEARCH_DOWN = new BinSearchDirection(2); + + /** + * author/date?? + * + * binary step size search used by outer_loop to get a quantizer step size + * to start with + */ + function bin_search_StepSize(gfc, cod_info, desired_rate, ch, xrpow) { + var nBits; + var CurrentStep = gfc.CurrentStep[ch]; + var flagGoneOver = false; + var start = gfc.OldValue[ch]; + var Direction = BinSearchDirection.BINSEARCH_NONE; + cod_info.global_gain = start; + desired_rate -= cod_info.part2_length; + + for (; ;) { + var step; + nBits = tk.count_bits(gfc, xrpow, cod_info, null); + + if (CurrentStep == 1 || nBits == desired_rate) + break; + /* nothing to adjust anymore */ + + if (nBits > desired_rate) { + /* increase Quantize_StepSize */ + if (Direction == BinSearchDirection.BINSEARCH_DOWN) + flagGoneOver = true; + + if (flagGoneOver) + CurrentStep /= 2; + Direction = BinSearchDirection.BINSEARCH_UP; + step = CurrentStep; + } else { + /* decrease Quantize_StepSize */ + if (Direction == BinSearchDirection.BINSEARCH_UP) + flagGoneOver = true; + + if (flagGoneOver) + CurrentStep /= 2; + Direction = BinSearchDirection.BINSEARCH_DOWN; + step = -CurrentStep; + } + cod_info.global_gain += step; + if (cod_info.global_gain < 0) { + cod_info.global_gain = 0; + flagGoneOver = true; + } + if (cod_info.global_gain > 255) { + cod_info.global_gain = 255; + flagGoneOver = true; + } + } + + + while (nBits > desired_rate && cod_info.global_gain < 255) { + cod_info.global_gain++; + nBits = tk.count_bits(gfc, xrpow, cod_info, null); + } + gfc.CurrentStep[ch] = (start - cod_info.global_gain >= 4) ? 4 : 2; + gfc.OldValue[ch] = cod_info.global_gain; + cod_info.part2_3_length = nBits; + return nBits; + } + + this.trancate_smallspectrums = function (gfc, gi, l3_xmin, work) { + var distort = new_float(L3Side.SFBMAX); + + if ((0 == (gfc.substep_shaping & 4) && gi.block_type == Encoder.SHORT_TYPE) + || (gfc.substep_shaping & 0x80) != 0) + return; + qupvt.calc_noise(gi, l3_xmin, distort, new CalcNoiseResult(), null); + for (var j = 0; j < 576; j++) { + var xr = 0.0; + if (gi.l3_enc[j] != 0) + xr = Math.abs(gi.xr[j]); + work[j] = xr; + } + + var j = 0; + var sfb = 8; + if (gi.block_type == Encoder.SHORT_TYPE) + sfb = 6; + do { + var allowedNoise, trancateThreshold; + var nsame, start; + + var width = gi.width[sfb]; + j += width; + if (distort[sfb] >= 1.0) + continue; + + Arrays.sort(work, j - width, width); + if (BitStream.EQ(work[j - 1], 0.0)) + continue; + /* all zero sfb */ + + allowedNoise = (1.0 - distort[sfb]) * l3_xmin[sfb]; + trancateThreshold = 0.0; + start = 0; + do { + var noise; + for (nsame = 1; start + nsame < width; nsame++) + if (BitStream.NEQ(work[start + j - width], work[start + j + + nsame - width])) + break; + + noise = work[start + j - width] * work[start + j - width] + * nsame; + if (allowedNoise < noise) { + if (start != 0) + trancateThreshold = work[start + j - width - 1]; + break; + } + allowedNoise -= noise; + start += nsame; + } while (start < width); + if (BitStream.EQ(trancateThreshold, 0.0)) + continue; + + do { + if (Math.abs(gi.xr[j - width]) <= trancateThreshold) + gi.l3_enc[j - width] = 0; + } while (--width > 0); + } while (++sfb < gi.psymax); + + gi.part2_3_length = tk.noquant_count_bits(gfc, gi, null); + }; + + /** + * author/date?? + * + * Function: Returns zero if there is a scalefac which has not been + * amplified. Otherwise it returns one. + */ + function loop_break(cod_info) { + for (var sfb = 0; sfb < cod_info.sfbmax; sfb++) + if (cod_info.scalefac[sfb] + + cod_info.subblock_gain[cod_info.window[sfb]] == 0) + return false; + + return true; + } + + /* mt 5/99: Function: Improved calc_noise for a single channel */ + + function penalties(noise) { + return Util.FAST_LOG10((0.368 + 0.632 * noise * noise * noise)); + } + + /** + * author/date?? + * + * several different codes to decide which quantization is better + */ + function get_klemm_noise(distort, gi) { + var klemm_noise = 1E-37; + for (var sfb = 0; sfb < gi.psymax; sfb++) + klemm_noise += penalties(distort[sfb]); + + return Math.max(1e-20, klemm_noise); + } + + function quant_compare(quant_comp, best, calc, gi, distort) { + /** + * noise is given in decibels (dB) relative to masking thesholds.
+ * + * over_noise: ??? (the previous comment is fully wrong)
+ * tot_noise: ??? (the previous comment is fully wrong)
+ * max_noise: max quantization noise + */ + var better; + + switch (quant_comp) { + default: + case 9: + { + if (best.over_count > 0) { + /* there are distorted sfb */ + better = calc.over_SSD <= best.over_SSD; + if (calc.over_SSD == best.over_SSD) + better = calc.bits < best.bits; + } else { + /* no distorted sfb */ + better = ((calc.max_noise < 0) && ((calc.max_noise * 10 + calc.bits) <= (best.max_noise * 10 + best.bits))); + } + break; + } + + case 0: + better = calc.over_count < best.over_count + || (calc.over_count == best.over_count && calc.over_noise < best.over_noise) + || (calc.over_count == best.over_count + && BitStream.EQ(calc.over_noise, best.over_noise) && calc.tot_noise < best.tot_noise); + break; + + case 8: + calc.max_noise = get_klemm_noise(distort, gi); + //$FALL-THROUGH$ + case 1: + better = calc.max_noise < best.max_noise; + break; + case 2: + better = calc.tot_noise < best.tot_noise; + break; + case 3: + better = (calc.tot_noise < best.tot_noise) + && (calc.max_noise < best.max_noise); + break; + case 4: + better = (calc.max_noise <= 0.0 && best.max_noise > 0.2) + || (calc.max_noise <= 0.0 && best.max_noise < 0.0 + && best.max_noise > calc.max_noise - 0.2 && calc.tot_noise < best.tot_noise) + || (calc.max_noise <= 0.0 && best.max_noise > 0.0 + && best.max_noise > calc.max_noise - 0.2 && calc.tot_noise < best.tot_noise + + best.over_noise) + || (calc.max_noise > 0.0 && best.max_noise > -0.05 + && best.max_noise > calc.max_noise - 0.1 && calc.tot_noise + + calc.over_noise < best.tot_noise + + best.over_noise) + || (calc.max_noise > 0.0 && best.max_noise > -0.1 + && best.max_noise > calc.max_noise - 0.15 && calc.tot_noise + + calc.over_noise + calc.over_noise < best.tot_noise + + best.over_noise + best.over_noise); + break; + case 5: + better = calc.over_noise < best.over_noise + || (BitStream.EQ(calc.over_noise, best.over_noise) && calc.tot_noise < best.tot_noise); + break; + case 6: + better = calc.over_noise < best.over_noise + || (BitStream.EQ(calc.over_noise, best.over_noise) && (calc.max_noise < best.max_noise || (BitStream + .EQ(calc.max_noise, best.max_noise) && calc.tot_noise <= best.tot_noise))); + break; + case 7: + better = calc.over_count < best.over_count + || calc.over_noise < best.over_noise; + break; + } + + if (best.over_count == 0) { + /* + * If no distorted bands, only use this quantization if it is + * better, and if it uses less bits. Unfortunately, part2_3_length + * is sometimes a poor estimator of the final size at low bitrates. + */ + better = better && calc.bits < best.bits; + } + + return better; + } + + /** + * author/date?? + * + *
+     *  Amplify the scalefactor bands that violate the masking threshold.
+     *  See ISO 11172-3 Section C.1.5.4.3.5
+     *
+     *  distort[] = noise/masking
+     *  distort[] > 1   ==> noise is not masked
+     *  distort[] < 1   ==> noise is masked
+     *  max_dist = maximum value of distort[]
+     *
+     *  Three algorithms:
+     *  noise_shaping_amp
+     *        0             Amplify all bands with distort[]>1.
+     *
+     *        1             Amplify all bands with distort[] >= max_dist^(.5);
+     *                     ( 50% in the db scale)
+     *
+     *        2             Amplify first band with distort[] >= max_dist;
+     *
+     *
+     *  For algorithms 0 and 1, if max_dist < 1, then amplify all bands
+     *  with distort[] >= .95*max_dist.  This is to make sure we always
+     *  amplify at least one band.
+     * 
+ */ + function amp_scalefac_bands(gfp, cod_info, distort, xrpow, bRefine) { + var gfc = gfp.internal_flags; + var ifqstep34; + + if (cod_info.scalefac_scale == 0) { + ifqstep34 = 1.29683955465100964055; + /* 2**(.75*.5) */ + } else { + ifqstep34 = 1.68179283050742922612; + /* 2**(.75*1) */ + } + + /* compute maximum value of distort[] */ + var trigger = 0; + for (var sfb = 0; sfb < cod_info.sfbmax; sfb++) { + if (trigger < distort[sfb]) + trigger = distort[sfb]; + } + + var noise_shaping_amp = gfc.noise_shaping_amp; + if (noise_shaping_amp == 3) { + if (bRefine) + noise_shaping_amp = 2; + else + noise_shaping_amp = 1; + } + switch (noise_shaping_amp) { + case 2: + /* amplify exactly 1 band */ + break; + + case 1: + /* amplify bands within 50% of max (on db scale) */ + if (trigger > 1.0) + trigger = Math.pow(trigger, .5); + else + trigger *= .95; + break; + + case 0: + default: + /* ISO algorithm. amplify all bands with distort>1 */ + if (trigger > 1.0) + trigger = 1.0; + else + trigger *= .95; + break; + } + + var j = 0; + for (var sfb = 0; sfb < cod_info.sfbmax; sfb++) { + var width = cod_info.width[sfb]; + var l; + j += width; + if (distort[sfb] < trigger) + continue; + + if ((gfc.substep_shaping & 2) != 0) { + gfc.pseudohalf[sfb] = (0 == gfc.pseudohalf[sfb]) ? 1 : 0; + if (0 == gfc.pseudohalf[sfb] && gfc.noise_shaping_amp == 2) + return; + } + cod_info.scalefac[sfb]++; + for (l = -width; l < 0; l++) { + xrpow[j + l] *= ifqstep34; + if (xrpow[j + l] > cod_info.xrpow_max) + cod_info.xrpow_max = xrpow[j + l]; + } + + if (gfc.noise_shaping_amp == 2) + return; + } + } + + /** + * Takehiro Tominaga 2000-xx-xx + * + * turns on scalefac scale and adjusts scalefactors + */ + function inc_scalefac_scale(cod_info, xrpow) { + var ifqstep34 = 1.29683955465100964055; + + var j = 0; + for (var sfb = 0; sfb < cod_info.sfbmax; sfb++) { + var width = cod_info.width[sfb]; + var s = cod_info.scalefac[sfb]; + if (cod_info.preflag != 0) + s += qupvt.pretab[sfb]; + j += width; + if ((s & 1) != 0) { + s++; + for (var l = -width; l < 0; l++) { + xrpow[j + l] *= ifqstep34; + if (xrpow[j + l] > cod_info.xrpow_max) + cod_info.xrpow_max = xrpow[j + l]; + } + } + cod_info.scalefac[sfb] = s >> 1; + } + cod_info.preflag = 0; + cod_info.scalefac_scale = 1; + } + + /** + * Takehiro Tominaga 2000-xx-xx + * + * increases the subblock gain and adjusts scalefactors + */ + function inc_subblock_gain(gfc, cod_info, xrpow) { + var sfb; + var scalefac = cod_info.scalefac; + + /* subbloc_gain can't do anything in the long block region */ + for (sfb = 0; sfb < cod_info.sfb_lmax; sfb++) { + if (scalefac[sfb] >= 16) + return true; + } + + for (var window = 0; window < 3; window++) { + var s1 = 0; + var s2 = 0; + + for (sfb = cod_info.sfb_lmax + window; sfb < cod_info.sfbdivide; sfb += 3) { + if (s1 < scalefac[sfb]) + s1 = scalefac[sfb]; + } + for (; sfb < cod_info.sfbmax; sfb += 3) { + if (s2 < scalefac[sfb]) + s2 = scalefac[sfb]; + } + + if (s1 < 16 && s2 < 8) + continue; + + if (cod_info.subblock_gain[window] >= 7) + return true; + + /* + * even though there is no scalefactor for sfb12 subblock gain + * affects upper frequencies too, that's why we have to go up to + * SBMAX_s + */ + cod_info.subblock_gain[window]++; + var j = gfc.scalefac_band.l[cod_info.sfb_lmax]; + for (sfb = cod_info.sfb_lmax + window; sfb < cod_info.sfbmax; sfb += 3) { + var amp; + var width = cod_info.width[sfb]; + var s = scalefac[sfb]; + s = s - (4 >> cod_info.scalefac_scale); + if (s >= 0) { + scalefac[sfb] = s; + j += width * 3; + continue; + } + + scalefac[sfb] = 0; + { + var gain = 210 + (s << (cod_info.scalefac_scale + 1)); + amp = qupvt.IPOW20(gain); + } + j += width * (window + 1); + for (var l = -width; l < 0; l++) { + xrpow[j + l] *= amp; + if (xrpow[j + l] > cod_info.xrpow_max) + cod_info.xrpow_max = xrpow[j + l]; + } + j += width * (3 - window - 1); + } + + { + var amp = qupvt.IPOW20(202); + j += cod_info.width[sfb] * (window + 1); + for (var l = -cod_info.width[sfb]; l < 0; l++) { + xrpow[j + l] *= amp; + if (xrpow[j + l] > cod_info.xrpow_max) + cod_info.xrpow_max = xrpow[j + l]; + } + } + } + return false; + } + + /** + *
+     *  Takehiro Tominaga /date??
+     *  Robert Hegemann 2000-09-06: made a function of it
+     *
+     *  amplifies scalefactor bands,
+     *   - if all are already amplified returns 0
+     *   - if some bands are amplified too much:
+     *      * try to increase scalefac_scale
+     *      * if already scalefac_scale was set
+     *          try on short blocks to increase subblock gain
+     * 
+ */ + function balance_noise(gfp, cod_info, distort, xrpow, bRefine) { + var gfc = gfp.internal_flags; + + amp_scalefac_bands(gfp, cod_info, distort, xrpow, bRefine); + + /* + * check to make sure we have not amplified too much loop_break returns + * 0 if there is an unamplified scalefac scale_bitcount returns 0 if no + * scalefactors are too large + */ + + var status = loop_break(cod_info); + + if (status) + return false; + /* all bands amplified */ + + /* + * not all scalefactors have been amplified. so these scalefacs are + * possibly valid. encode them: + */ + if (gfc.mode_gr == 2) + status = tk.scale_bitcount(cod_info); + else + status = tk.scale_bitcount_lsf(gfc, cod_info); + + if (!status) + return true; + /* amplified some bands not exceeding limits */ + + /* + * some scalefactors are too large. lets try setting scalefac_scale=1 + */ + if (gfc.noise_shaping > 1) { + Arrays.fill(gfc.pseudohalf, 0); + if (0 == cod_info.scalefac_scale) { + inc_scalefac_scale(cod_info, xrpow); + status = false; + } else { + if (cod_info.block_type == Encoder.SHORT_TYPE + && gfc.subblock_gain > 0) { + status = (inc_subblock_gain(gfc, cod_info, xrpow) || loop_break(cod_info)); + } + } + } + + if (!status) { + if (gfc.mode_gr == 2) + status = tk.scale_bitcount(cod_info); + else + status = tk.scale_bitcount_lsf(gfc, cod_info); + } + return !status; + } + + /** + *
+     *  Function: The outer iteration loop controls the masking conditions
+     *  of all scalefactorbands. It computes the best scalefac and
+     *  global gain. This module calls the inner iteration loop
+     *
+     *  mt 5/99 completely rewritten to allow for bit reservoir control,
+     *  mid/side channels with L/R or mid/side masking thresholds,
+     *  and chooses best quantization instead of last quantization when
+     *  no distortion free quantization can be found.
+     *
+     *  added VBR support mt 5/99
+     *
+     *  some code shuffle rh 9/00
+     * 
+ * + * @param l3_xmin + * allowed distortion + * @param xrpow + * coloured magnitudes of spectral + * @param targ_bits + * maximum allowed bits + */ + this.outer_loop = function (gfp, cod_info, l3_xmin, xrpow, ch, targ_bits) { + var gfc = gfp.internal_flags; + var cod_info_w = new GrInfo(); + var save_xrpow = new_float(576); + var distort = new_float(L3Side.SFBMAX); + var best_noise_info = new CalcNoiseResult(); + var better; + var prev_noise = new CalcNoiseData(); + var best_part2_3_length = 9999999; + var bEndOfSearch = false; + var bRefine = false; + var best_ggain_pass1 = 0; + + bin_search_StepSize(gfc, cod_info, targ_bits, ch, xrpow); + + if (0 == gfc.noise_shaping) + /* fast mode, no noise shaping, we are ready */ + return 100; + /* default noise_info.over_count */ + + /* compute the distortion in this quantization */ + /* coefficients and thresholds both l/r (or both mid/side) */ + qupvt.calc_noise(cod_info, l3_xmin, distort, best_noise_info, + prev_noise); + best_noise_info.bits = cod_info.part2_3_length; + + cod_info_w.assign(cod_info); + var age = 0; + System.arraycopy(xrpow, 0, save_xrpow, 0, 576); + + while (!bEndOfSearch) { + /* BEGIN MAIN LOOP */ + do { + var noise_info = new CalcNoiseResult(); + var search_limit; + var maxggain = 255; + + /* + * When quantization with no distorted bands is found, allow up + * to X new unsuccesful tries in serial. This gives us more + * possibilities for different quant_compare modes. Much more + * than 3 makes not a big difference, it is only slower. + */ + + if ((gfc.substep_shaping & 2) != 0) { + search_limit = 20; + } else { + search_limit = 3; + } + + /* + * Check if the last scalefactor band is distorted. in VBR mode + * we can't get rid of the distortion, so quit now and VBR mode + * will try again with more bits. (makes a 10% speed increase, + * the files I tested were binary identical, 2000/05/20 Robert + * Hegemann) distort[] > 1 means noise > allowed noise + */ + if (gfc.sfb21_extra) { + if (distort[cod_info_w.sfbmax] > 1.0) + break; + if (cod_info_w.block_type == Encoder.SHORT_TYPE + && (distort[cod_info_w.sfbmax + 1] > 1.0 || distort[cod_info_w.sfbmax + 2] > 1.0)) + break; + } + + /* try a new scalefactor conbination on cod_info_w */ + if (!balance_noise(gfp, cod_info_w, distort, xrpow, bRefine)) + break; + if (cod_info_w.scalefac_scale != 0) + maxggain = 254; + + /* + * inner_loop starts with the initial quantization step computed + * above and slowly increases until the bits < huff_bits. Thus + * it is important not to start with too large of an inital + * quantization step. Too small is ok, but inner_loop will take + * longer + */ + var huff_bits = targ_bits - cod_info_w.part2_length; + if (huff_bits <= 0) + break; + + /* + * increase quantizer stepsize until needed bits are below + * maximum + */ + while ((cod_info_w.part2_3_length = tk.count_bits(gfc, xrpow, + cod_info_w, prev_noise)) > huff_bits + && cod_info_w.global_gain <= maxggain) + cod_info_w.global_gain++; + + if (cod_info_w.global_gain > maxggain) + break; + + if (best_noise_info.over_count == 0) { + + while ((cod_info_w.part2_3_length = tk.count_bits(gfc, + xrpow, cod_info_w, prev_noise)) > best_part2_3_length + && cod_info_w.global_gain <= maxggain) + cod_info_w.global_gain++; + + if (cod_info_w.global_gain > maxggain) + break; + } + + /* compute the distortion in this quantization */ + qupvt.calc_noise(cod_info_w, l3_xmin, distort, noise_info, + prev_noise); + noise_info.bits = cod_info_w.part2_3_length; + + /* + * check if this quantization is better than our saved + * quantization + */ + if (cod_info.block_type != Encoder.SHORT_TYPE) { + // NORM, START or STOP type + better = gfp.quant_comp; + } else + better = gfp.quant_comp_short; + + better = quant_compare(better, best_noise_info, noise_info, + cod_info_w, distort) ? 1 : 0; + + /* save data so we can restore this quantization later */ + if (better != 0) { + best_part2_3_length = cod_info.part2_3_length; + best_noise_info = noise_info; + cod_info.assign(cod_info_w); + age = 0; + /* save data so we can restore this quantization later */ + /* store for later reuse */ + System.arraycopy(xrpow, 0, save_xrpow, 0, 576); + } else { + /* early stop? */ + if (gfc.full_outer_loop == 0) { + if (++age > search_limit + && best_noise_info.over_count == 0) + break; + if ((gfc.noise_shaping_amp == 3) && bRefine && age > 30) + break; + if ((gfc.noise_shaping_amp == 3) + && bRefine + && (cod_info_w.global_gain - best_ggain_pass1) > 15) + break; + } + } + } while ((cod_info_w.global_gain + cod_info_w.scalefac_scale) < 255); + + if (gfc.noise_shaping_amp == 3) { + if (!bRefine) { + /* refine search */ + cod_info_w.assign(cod_info); + System.arraycopy(save_xrpow, 0, xrpow, 0, 576); + age = 0; + best_ggain_pass1 = cod_info_w.global_gain; + + bRefine = true; + } else { + /* search already refined, stop */ + bEndOfSearch = true; + } + + } else { + bEndOfSearch = true; + } + } + + /* + * finish up + */ + if (gfp.VBR == VbrMode.vbr_rh || gfp.VBR == VbrMode.vbr_mtrh) + /* restore for reuse on next try */ + System.arraycopy(save_xrpow, 0, xrpow, 0, 576); + /* + * do the 'substep shaping' + */ + else if ((gfc.substep_shaping & 1) != 0) + trancate_smallspectrums(gfc, cod_info, l3_xmin, xrpow); + + return best_noise_info.over_count; + } + + /** + * Robert Hegemann 2000-09-06 + * + * update reservoir status after FINAL quantization/bitrate + */ + this.iteration_finish_one = function (gfc, gr, ch) { + var l3_side = gfc.l3_side; + var cod_info = l3_side.tt[gr][ch]; + + /* + * try some better scalefac storage + */ + tk.best_scalefac_store(gfc, gr, ch, l3_side); + + /* + * best huffman_divide may save some bits too + */ + if (gfc.use_best_huffman == 1) + tk.best_huffman_divide(gfc, cod_info); + + /* + * update reservoir status after FINAL quantization/bitrate + */ + rv.ResvAdjust(gfc, cod_info); + }; + + /** + * + * 2000-09-04 Robert Hegemann + * + * @param l3_xmin + * allowed distortion of the scalefactor + * @param xrpow + * coloured magnitudes of spectral values + */ + this.VBR_encode_granule = function (gfp, cod_info, l3_xmin, xrpow, ch, min_bits, max_bits) { + var gfc = gfp.internal_flags; + var bst_cod_info = new GrInfo(); + var bst_xrpow = new_float(576); + var Max_bits = max_bits; + var real_bits = max_bits + 1; + var this_bits = (max_bits + min_bits) / 2; + var dbits, over, found = 0; + var sfb21_extra = gfc.sfb21_extra; + + Arrays.fill(bst_cod_info.l3_enc, 0); + + /* + * search within round about 40 bits of optimal + */ + do { + + if (this_bits > Max_bits - 42) + gfc.sfb21_extra = false; + else + gfc.sfb21_extra = sfb21_extra; + + over = outer_loop(gfp, cod_info, l3_xmin, xrpow, ch, this_bits); + + /* + * is quantization as good as we are looking for ? in this case: is + * no scalefactor band distorted? + */ + if (over <= 0) { + found = 1; + /* + * now we know it can be done with "real_bits" and maybe we can + * skip some iterations + */ + real_bits = cod_info.part2_3_length; + + /* + * store best quantization so far + */ + bst_cod_info.assign(cod_info); + System.arraycopy(xrpow, 0, bst_xrpow, 0, 576); + + /* + * try with fewer bits + */ + max_bits = real_bits - 32; + dbits = max_bits - min_bits; + this_bits = (max_bits + min_bits) / 2; + } else { + /* + * try with more bits + */ + min_bits = this_bits + 32; + dbits = max_bits - min_bits; + this_bits = (max_bits + min_bits) / 2; + + if (found != 0) { + found = 2; + /* + * start again with best quantization so far + */ + cod_info.assign(bst_cod_info); + System.arraycopy(bst_xrpow, 0, xrpow, 0, 576); + } + } + } while (dbits > 12); + + gfc.sfb21_extra = sfb21_extra; + + /* + * found=0 => nothing found, use last one found=1 => we just found the + * best and left the loop found=2 => we restored a good one and have now + * l3_enc to restore too + */ + if (found == 2) { + System.arraycopy(bst_cod_info.l3_enc, 0, cod_info.l3_enc, 0, 576); + } + } + + /** + * Robert Hegemann 2000-09-05 + * + * calculates * how many bits are available for analog silent granules * how + * many bits to use for the lowest allowed bitrate * how many bits each + * bitrate would provide + */ + this.get_framebits = function (gfp, frameBits) { + var gfc = gfp.internal_flags; + + /* + * always use at least this many bits per granule per channel unless we + * detect analog silence, see below + */ + gfc.bitrate_index = gfc.VBR_min_bitrate; + var bitsPerFrame = bs.getframebits(gfp); + + /* + * bits for analog silence + */ + gfc.bitrate_index = 1; + bitsPerFrame = bs.getframebits(gfp); + + for (var i = 1; i <= gfc.VBR_max_bitrate; i++) { + gfc.bitrate_index = i; + var mb = new MeanBits(bitsPerFrame); + frameBits[i] = rv.ResvFrameBegin(gfp, mb); + bitsPerFrame = mb.bits; + } + }; + + /* RH: this one needs to be overhauled sometime */ + + /** + *
+     *  2000-09-04 Robert Hegemann
+     *
+     *  * converts LR to MS coding when necessary
+     *  * calculates allowed/adjusted quantization noise amounts
+     *  * detects analog silent frames
+     *
+     *  some remarks:
+     *  - lower masking depending on Quality setting
+     *  - quality control together with adjusted ATH MDCT scaling
+     *    on lower quality setting allocate more noise from
+     *    ATH masking, and on higher quality setting allocate
+     *    less noise from ATH masking.
+     *  - experiments show that going more than 2dB over GPSYCHO's
+     *    limits ends up in very annoying artefacts
+     * 
+ */ + this.VBR_old_prepare = function (gfp, pe, ms_ener_ratio, ratio, l3_xmin, frameBits, min_bits, + max_bits, bands) { + var gfc = gfp.internal_flags; + + var masking_lower_db, adjust = 0.0; + var analog_silence = 1; + var bits = 0; + + gfc.bitrate_index = gfc.VBR_max_bitrate; + var avg = rv.ResvFrameBegin(gfp, new MeanBits(0)) / gfc.mode_gr; + + get_framebits(gfp, frameBits); + + for (var gr = 0; gr < gfc.mode_gr; gr++) { + var mxb = qupvt.on_pe(gfp, pe, max_bits[gr], avg, gr, 0); + if (gfc.mode_ext == Encoder.MPG_MD_MS_LR) { + ms_convert(gfc.l3_side, gr); + qupvt.reduce_side(max_bits[gr], ms_ener_ratio[gr], avg, mxb); + } + for (var ch = 0; ch < gfc.channels_out; ++ch) { + var cod_info = gfc.l3_side.tt[gr][ch]; + + if (cod_info.block_type != Encoder.SHORT_TYPE) { + // NORM, START or STOP type + adjust = 1.28 / (1 + Math + .exp(3.5 - pe[gr][ch] / 300.)) - 0.05; + masking_lower_db = gfc.PSY.mask_adjust - adjust; + } else { + adjust = 2.56 / (1 + Math + .exp(3.5 - pe[gr][ch] / 300.)) - 0.14; + masking_lower_db = gfc.PSY.mask_adjust_short - adjust; + } + gfc.masking_lower = Math.pow(10.0, + masking_lower_db * 0.1); + + init_outer_loop(gfc, cod_info); + bands[gr][ch] = qupvt.calc_xmin(gfp, ratio[gr][ch], cod_info, + l3_xmin[gr][ch]); + if (bands[gr][ch] != 0) + analog_silence = 0; + + min_bits[gr][ch] = 126; + + bits += max_bits[gr][ch]; + } + } + for (var gr = 0; gr < gfc.mode_gr; gr++) { + for (var ch = 0; ch < gfc.channels_out; ch++) { + if (bits > frameBits[gfc.VBR_max_bitrate]) { + max_bits[gr][ch] *= frameBits[gfc.VBR_max_bitrate]; + max_bits[gr][ch] /= bits; + } + if (min_bits[gr][ch] > max_bits[gr][ch]) + min_bits[gr][ch] = max_bits[gr][ch]; + + } + /* for ch */ + } + /* for gr */ + + return analog_silence; + }; + + this.bitpressure_strategy = function (gfc, l3_xmin, min_bits, max_bits) { + for (var gr = 0; gr < gfc.mode_gr; gr++) { + for (var ch = 0; ch < gfc.channels_out; ch++) { + var gi = gfc.l3_side.tt[gr][ch]; + var pxmin = l3_xmin[gr][ch]; + var pxminPos = 0; + for (var sfb = 0; sfb < gi.psy_lmax; sfb++) + pxmin[pxminPos++] *= 1. + .029 * sfb * sfb + / Encoder.SBMAX_l / Encoder.SBMAX_l; + + if (gi.block_type == Encoder.SHORT_TYPE) { + for (var sfb = gi.sfb_smin; sfb < Encoder.SBMAX_s; sfb++) { + pxmin[pxminPos++] *= 1. + .029 * sfb * sfb + / Encoder.SBMAX_s / Encoder.SBMAX_s; + pxmin[pxminPos++] *= 1. + .029 * sfb * sfb + / Encoder.SBMAX_s / Encoder.SBMAX_s; + pxmin[pxminPos++] *= 1. + .029 * sfb * sfb + / Encoder.SBMAX_s / Encoder.SBMAX_s; + } + } + max_bits[gr][ch] = 0 | Math.max(min_bits[gr][ch], + 0.9 * max_bits[gr][ch]); + } + } + }; + + this.VBR_new_prepare = function (gfp, pe, ratio, l3_xmin, frameBits, max_bits) { + var gfc = gfp.internal_flags; + + var analog_silence = 1; + var avg = 0, bits = 0; + var maximum_framebits; + + if (!gfp.free_format) { + gfc.bitrate_index = gfc.VBR_max_bitrate; + + var mb = new MeanBits(avg); + rv.ResvFrameBegin(gfp, mb); + avg = mb.bits; + + get_framebits(gfp, frameBits); + maximum_framebits = frameBits[gfc.VBR_max_bitrate]; + } else { + gfc.bitrate_index = 0; + var mb = new MeanBits(avg); + maximum_framebits = rv.ResvFrameBegin(gfp, mb); + avg = mb.bits; + frameBits[0] = maximum_framebits; + } + + for (var gr = 0; gr < gfc.mode_gr; gr++) { + qupvt.on_pe(gfp, pe, max_bits[gr], avg, gr, 0); + if (gfc.mode_ext == Encoder.MPG_MD_MS_LR) { + ms_convert(gfc.l3_side, gr); + } + for (var ch = 0; ch < gfc.channels_out; ++ch) { + var cod_info = gfc.l3_side.tt[gr][ch]; + + gfc.masking_lower = Math.pow(10.0, + gfc.PSY.mask_adjust * 0.1); + + init_outer_loop(gfc, cod_info); + if (0 != qupvt.calc_xmin(gfp, ratio[gr][ch], cod_info, + l3_xmin[gr][ch])) + analog_silence = 0; + + bits += max_bits[gr][ch]; + } + } + for (var gr = 0; gr < gfc.mode_gr; gr++) { + for (var ch = 0; ch < gfc.channels_out; ch++) { + if (bits > maximum_framebits) { + max_bits[gr][ch] *= maximum_framebits; + max_bits[gr][ch] /= bits; + } + + } + /* for ch */ + } + /* for gr */ + + return analog_silence; + }; + + /** + * calculates target bits for ABR encoding + * + * mt 2000/05/31 + */ + this.calc_target_bits = function (gfp, pe, ms_ener_ratio, targ_bits, analog_silence_bits, max_frame_bits) { + var gfc = gfp.internal_flags; + var l3_side = gfc.l3_side; + var res_factor; + var gr, ch, totbits, mean_bits = 0; + + gfc.bitrate_index = gfc.VBR_max_bitrate; + var mb = new MeanBits(mean_bits); + max_frame_bits[0] = rv.ResvFrameBegin(gfp, mb); + mean_bits = mb.bits; + + gfc.bitrate_index = 1; + mean_bits = bs.getframebits(gfp) - gfc.sideinfo_len * 8; + analog_silence_bits[0] = mean_bits / (gfc.mode_gr * gfc.channels_out); + + mean_bits = gfp.VBR_mean_bitrate_kbps * gfp.framesize * 1000; + if ((gfc.substep_shaping & 1) != 0) + mean_bits *= 1.09; + mean_bits /= gfp.out_samplerate; + mean_bits -= gfc.sideinfo_len * 8; + mean_bits /= (gfc.mode_gr * gfc.channels_out); + + /** + *
+         *           res_factor is the percentage of the target bitrate that should
+         *           be used on average.  the remaining bits are added to the
+         *           bitreservoir and used for difficult to encode frames.
+         *
+         *           Since we are tracking the average bitrate, we should adjust
+         *           res_factor "on the fly", increasing it if the average bitrate
+         *           is greater than the requested bitrate, and decreasing it
+         *           otherwise.  Reasonable ranges are from .9 to 1.0
+         *
+         *           Until we get the above suggestion working, we use the following
+         *           tuning:
+         *           compression ratio    res_factor
+         *           5.5  (256kbps)         1.0      no need for bitreservoir
+         *           11   (128kbps)         .93      7% held for reservoir
+         *
+         *           with linear interpolation for other values.
+         * 
+ */ + res_factor = .93 + .07 * (11.0 - gfp.compression_ratio) + / (11.0 - 5.5); + if (res_factor < .90) + res_factor = .90; + if (res_factor > 1.00) + res_factor = 1.00; + + for (gr = 0; gr < gfc.mode_gr; gr++) { + var sum = 0; + for (ch = 0; ch < gfc.channels_out; ch++) { + targ_bits[gr][ch] = (int)(res_factor * mean_bits); + + if (pe[gr][ch] > 700) { + var add_bits = (int)((pe[gr][ch] - 700) / 1.4); + + var cod_info = l3_side.tt[gr][ch]; + targ_bits[gr][ch] = (int)(res_factor * mean_bits); + + /* short blocks use a little extra, no matter what the pe */ + if (cod_info.block_type == Encoder.SHORT_TYPE) { + if (add_bits < mean_bits / 2) + add_bits = mean_bits / 2; + } + /* at most increase bits by 1.5*average */ + if (add_bits > mean_bits * 3 / 2) + add_bits = mean_bits * 3 / 2; + else if (add_bits < 0) + add_bits = 0; + + targ_bits[gr][ch] += add_bits; + } + if (targ_bits[gr][ch] > LameInternalFlags.MAX_BITS_PER_CHANNEL) { + targ_bits[gr][ch] = LameInternalFlags.MAX_BITS_PER_CHANNEL; + } + sum += targ_bits[gr][ch]; + } + /* for ch */ + if (sum > LameInternalFlags.MAX_BITS_PER_GRANULE) { + for (ch = 0; ch < gfc.channels_out; ++ch) { + targ_bits[gr][ch] *= LameInternalFlags.MAX_BITS_PER_GRANULE; + targ_bits[gr][ch] /= sum; + } + } + } + /* for gr */ + + if (gfc.mode_ext == Encoder.MPG_MD_MS_LR) + for (gr = 0; gr < gfc.mode_gr; gr++) { + qupvt.reduce_side(targ_bits[gr], ms_ener_ratio[gr], mean_bits + * gfc.channels_out, + LameInternalFlags.MAX_BITS_PER_GRANULE); + } + + /* + * sum target bits + */ + totbits = 0; + for (gr = 0; gr < gfc.mode_gr; gr++) { + for (ch = 0; ch < gfc.channels_out; ch++) { + if (targ_bits[gr][ch] > LameInternalFlags.MAX_BITS_PER_CHANNEL) + targ_bits[gr][ch] = LameInternalFlags.MAX_BITS_PER_CHANNEL; + totbits += targ_bits[gr][ch]; + } + } + + /* + * repartion target bits if needed + */ + if (totbits > max_frame_bits[0]) { + for (gr = 0; gr < gfc.mode_gr; gr++) { + for (ch = 0; ch < gfc.channels_out; ch++) { + targ_bits[gr][ch] *= max_frame_bits[0]; + targ_bits[gr][ch] /= totbits; + } + } + } + } + +} + +/* + * MP3 window subband -> subband filtering -> mdct routine + * + * Copyright (c) 1999-2000 Takehiro Tominaga + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* + * Special Thanks to Patrick De Smet for your advices. + */ + +/* $Id: NewMDCT.java,v 1.11 2011/05/24 20:48:06 kenchis Exp $ */ + +//package mp3; + +//import java.util.Arrays; + + + +function NewMDCT() { + + var enwindow = [ + -4.77e-07 * 0.740951125354959 / 2.384e-06, + 1.03951e-04 * 0.740951125354959 / 2.384e-06, + 9.53674e-04 * 0.740951125354959 / 2.384e-06, + 2.841473e-03 * 0.740951125354959 / 2.384e-06, + 3.5758972e-02 * 0.740951125354959 / 2.384e-06, + 3.401756e-03 * 0.740951125354959 / 2.384e-06, + 9.83715e-04 * 0.740951125354959 / 2.384e-06, + 9.9182e-05 * 0.740951125354959 / 2.384e-06, /* 15 */ + 1.2398e-05 * 0.740951125354959 / 2.384e-06, + 1.91212e-04 * 0.740951125354959 / 2.384e-06, + 2.283096e-03 * 0.740951125354959 / 2.384e-06, + 1.6994476e-02 * 0.740951125354959 / 2.384e-06, + -1.8756866e-02 * 0.740951125354959 / 2.384e-06, + -2.630711e-03 * 0.740951125354959 / 2.384e-06, + -2.47478e-04 * 0.740951125354959 / 2.384e-06, + -1.4782e-05 * 0.740951125354959 / 2.384e-06, + 9.063471690191471e-01, 1.960342806591213e-01, + + -4.77e-07 * 0.773010453362737 / 2.384e-06, + 1.05858e-04 * 0.773010453362737 / 2.384e-06, + 9.30786e-04 * 0.773010453362737 / 2.384e-06, + 2.521515e-03 * 0.773010453362737 / 2.384e-06, + 3.5694122e-02 * 0.773010453362737 / 2.384e-06, + 3.643036e-03 * 0.773010453362737 / 2.384e-06, + 9.91821e-04 * 0.773010453362737 / 2.384e-06, + 9.6321e-05 * 0.773010453362737 / 2.384e-06, /* 14 */ + 1.1444e-05 * 0.773010453362737 / 2.384e-06, + 1.65462e-04 * 0.773010453362737 / 2.384e-06, + 2.110004e-03 * 0.773010453362737 / 2.384e-06, + 1.6112804e-02 * 0.773010453362737 / 2.384e-06, + -1.9634247e-02 * 0.773010453362737 / 2.384e-06, + -2.803326e-03 * 0.773010453362737 / 2.384e-06, + -2.77042e-04 * 0.773010453362737 / 2.384e-06, + -1.6689e-05 * 0.773010453362737 / 2.384e-06, + 8.206787908286602e-01, 3.901806440322567e-01, + + -4.77e-07 * 0.803207531480645 / 2.384e-06, + 1.07288e-04 * 0.803207531480645 / 2.384e-06, + 9.02653e-04 * 0.803207531480645 / 2.384e-06, + 2.174854e-03 * 0.803207531480645 / 2.384e-06, + 3.5586357e-02 * 0.803207531480645 / 2.384e-06, + 3.858566e-03 * 0.803207531480645 / 2.384e-06, + 9.95159e-04 * 0.803207531480645 / 2.384e-06, + 9.3460e-05 * 0.803207531480645 / 2.384e-06, /* 13 */ + 1.0014e-05 * 0.803207531480645 / 2.384e-06, + 1.40190e-04 * 0.803207531480645 / 2.384e-06, + 1.937389e-03 * 0.803207531480645 / 2.384e-06, + 1.5233517e-02 * 0.803207531480645 / 2.384e-06, + -2.0506859e-02 * 0.803207531480645 / 2.384e-06, + -2.974033e-03 * 0.803207531480645 / 2.384e-06, + -3.07560e-04 * 0.803207531480645 / 2.384e-06, + -1.8120e-05 * 0.803207531480645 / 2.384e-06, + 7.416505462720353e-01, 5.805693545089249e-01, + + -4.77e-07 * 0.831469612302545 / 2.384e-06, + 1.08242e-04 * 0.831469612302545 / 2.384e-06, + 8.68797e-04 * 0.831469612302545 / 2.384e-06, + 1.800537e-03 * 0.831469612302545 / 2.384e-06, + 3.5435200e-02 * 0.831469612302545 / 2.384e-06, + 4.049301e-03 * 0.831469612302545 / 2.384e-06, + 9.94205e-04 * 0.831469612302545 / 2.384e-06, + 9.0599e-05 * 0.831469612302545 / 2.384e-06, /* 12 */ + 9.060e-06 * 0.831469612302545 / 2.384e-06, + 1.16348e-04 * 0.831469612302545 / 2.384e-06, + 1.766682e-03 * 0.831469612302545 / 2.384e-06, + 1.4358521e-02 * 0.831469612302545 / 2.384e-06, + -2.1372318e-02 * 0.831469612302545 / 2.384e-06, + -3.14188e-03 * 0.831469612302545 / 2.384e-06, + -3.39031e-04 * 0.831469612302545 / 2.384e-06, + -1.9550e-05 * 0.831469612302545 / 2.384e-06, + 6.681786379192989e-01, 7.653668647301797e-01, + + -4.77e-07 * 0.857728610000272 / 2.384e-06, + 1.08719e-04 * 0.857728610000272 / 2.384e-06, + 8.29220e-04 * 0.857728610000272 / 2.384e-06, + 1.399517e-03 * 0.857728610000272 / 2.384e-06, + 3.5242081e-02 * 0.857728610000272 / 2.384e-06, + 4.215240e-03 * 0.857728610000272 / 2.384e-06, + 9.89437e-04 * 0.857728610000272 / 2.384e-06, + 8.7261e-05 * 0.857728610000272 / 2.384e-06, /* 11 */ + 8.106e-06 * 0.857728610000272 / 2.384e-06, + 9.3937e-05 * 0.857728610000272 / 2.384e-06, + 1.597881e-03 * 0.857728610000272 / 2.384e-06, + 1.3489246e-02 * 0.857728610000272 / 2.384e-06, + -2.2228718e-02 * 0.857728610000272 / 2.384e-06, + -3.306866e-03 * 0.857728610000272 / 2.384e-06, + -3.71456e-04 * 0.857728610000272 / 2.384e-06, + -2.1458e-05 * 0.857728610000272 / 2.384e-06, + 5.993769336819237e-01, 9.427934736519954e-01, + + -4.77e-07 * 0.881921264348355 / 2.384e-06, + 1.08719e-04 * 0.881921264348355 / 2.384e-06, + 7.8392e-04 * 0.881921264348355 / 2.384e-06, + 9.71317e-04 * 0.881921264348355 / 2.384e-06, + 3.5007000e-02 * 0.881921264348355 / 2.384e-06, + 4.357815e-03 * 0.881921264348355 / 2.384e-06, + 9.80854e-04 * 0.881921264348355 / 2.384e-06, + 8.3923e-05 * 0.881921264348355 / 2.384e-06, /* 10 */ + 7.629e-06 * 0.881921264348355 / 2.384e-06, + 7.2956e-05 * 0.881921264348355 / 2.384e-06, + 1.432419e-03 * 0.881921264348355 / 2.384e-06, + 1.2627602e-02 * 0.881921264348355 / 2.384e-06, + -2.3074150e-02 * 0.881921264348355 / 2.384e-06, + -3.467083e-03 * 0.881921264348355 / 2.384e-06, + -4.04358e-04 * 0.881921264348355 / 2.384e-06, + -2.3365e-05 * 0.881921264348355 / 2.384e-06, + 5.345111359507916e-01, 1.111140466039205e+00, + + -9.54e-07 * 0.903989293123443 / 2.384e-06, + 1.08242e-04 * 0.903989293123443 / 2.384e-06, + 7.31945e-04 * 0.903989293123443 / 2.384e-06, + 5.15938e-04 * 0.903989293123443 / 2.384e-06, + 3.4730434e-02 * 0.903989293123443 / 2.384e-06, + 4.477024e-03 * 0.903989293123443 / 2.384e-06, + 9.68933e-04 * 0.903989293123443 / 2.384e-06, + 8.0585e-05 * 0.903989293123443 / 2.384e-06, /* 9 */ + 6.676e-06 * 0.903989293123443 / 2.384e-06, + 5.2929e-05 * 0.903989293123443 / 2.384e-06, + 1.269817e-03 * 0.903989293123443 / 2.384e-06, + 1.1775017e-02 * 0.903989293123443 / 2.384e-06, + -2.3907185e-02 * 0.903989293123443 / 2.384e-06, + -3.622532e-03 * 0.903989293123443 / 2.384e-06, + -4.38213e-04 * 0.903989293123443 / 2.384e-06, + -2.5272e-05 * 0.903989293123443 / 2.384e-06, + 4.729647758913199e-01, 1.268786568327291e+00, + + -9.54e-07 * 0.92387953251128675613 / 2.384e-06, + 1.06812e-04 * 0.92387953251128675613 / 2.384e-06, + 6.74248e-04 * 0.92387953251128675613 / 2.384e-06, + 3.3379e-05 * 0.92387953251128675613 / 2.384e-06, + 3.4412861e-02 * 0.92387953251128675613 / 2.384e-06, + 4.573822e-03 * 0.92387953251128675613 / 2.384e-06, + 9.54151e-04 * 0.92387953251128675613 / 2.384e-06, + 7.6771e-05 * 0.92387953251128675613 / 2.384e-06, + 6.199e-06 * 0.92387953251128675613 / 2.384e-06, + 3.4332e-05 * 0.92387953251128675613 / 2.384e-06, + 1.111031e-03 * 0.92387953251128675613 / 2.384e-06, + 1.0933399e-02 * 0.92387953251128675613 / 2.384e-06, + -2.4725437e-02 * 0.92387953251128675613 / 2.384e-06, + -3.771782e-03 * 0.92387953251128675613 / 2.384e-06, + -4.72546e-04 * 0.92387953251128675613 / 2.384e-06, + -2.7657e-05 * 0.92387953251128675613 / 2.384e-06, + 4.1421356237309504879e-01, /* tan(PI/8) */ + 1.414213562373095e+00, + + -9.54e-07 * 0.941544065183021 / 2.384e-06, + 1.05381e-04 * 0.941544065183021 / 2.384e-06, + 6.10352e-04 * 0.941544065183021 / 2.384e-06, + -4.75883e-04 * 0.941544065183021 / 2.384e-06, + 3.4055710e-02 * 0.941544065183021 / 2.384e-06, + 4.649162e-03 * 0.941544065183021 / 2.384e-06, + 9.35555e-04 * 0.941544065183021 / 2.384e-06, + 7.3433e-05 * 0.941544065183021 / 2.384e-06, /* 7 */ + 5.245e-06 * 0.941544065183021 / 2.384e-06, + 1.7166e-05 * 0.941544065183021 / 2.384e-06, + 9.56535e-04 * 0.941544065183021 / 2.384e-06, + 1.0103703e-02 * 0.941544065183021 / 2.384e-06, + -2.5527000e-02 * 0.941544065183021 / 2.384e-06, + -3.914356e-03 * 0.941544065183021 / 2.384e-06, + -5.07355e-04 * 0.941544065183021 / 2.384e-06, + -3.0041e-05 * 0.941544065183021 / 2.384e-06, + 3.578057213145241e-01, 1.546020906725474e+00, + + -9.54e-07 * 0.956940335732209 / 2.384e-06, + 1.02520e-04 * 0.956940335732209 / 2.384e-06, + 5.39303e-04 * 0.956940335732209 / 2.384e-06, + -1.011848e-03 * 0.956940335732209 / 2.384e-06, + 3.3659935e-02 * 0.956940335732209 / 2.384e-06, + 4.703045e-03 * 0.956940335732209 / 2.384e-06, + 9.15051e-04 * 0.956940335732209 / 2.384e-06, + 7.0095e-05 * 0.956940335732209 / 2.384e-06, /* 6 */ + 4.768e-06 * 0.956940335732209 / 2.384e-06, + 9.54e-07 * 0.956940335732209 / 2.384e-06, + 8.06808e-04 * 0.956940335732209 / 2.384e-06, + 9.287834e-03 * 0.956940335732209 / 2.384e-06, + -2.6310921e-02 * 0.956940335732209 / 2.384e-06, + -4.048824e-03 * 0.956940335732209 / 2.384e-06, + -5.42164e-04 * 0.956940335732209 / 2.384e-06, + -3.2425e-05 * 0.956940335732209 / 2.384e-06, + 3.033466836073424e-01, 1.662939224605090e+00, + + -1.431e-06 * 0.970031253194544 / 2.384e-06, + 9.9182e-05 * 0.970031253194544 / 2.384e-06, + 4.62532e-04 * 0.970031253194544 / 2.384e-06, + -1.573563e-03 * 0.970031253194544 / 2.384e-06, + 3.3225536e-02 * 0.970031253194544 / 2.384e-06, + 4.737377e-03 * 0.970031253194544 / 2.384e-06, + 8.91685e-04 * 0.970031253194544 / 2.384e-06, + 6.6280e-05 * 0.970031253194544 / 2.384e-06, /* 5 */ + 4.292e-06 * 0.970031253194544 / 2.384e-06, + -1.3828e-05 * 0.970031253194544 / 2.384e-06, + 6.61850e-04 * 0.970031253194544 / 2.384e-06, + 8.487225e-03 * 0.970031253194544 / 2.384e-06, + -2.7073860e-02 * 0.970031253194544 / 2.384e-06, + -4.174709e-03 * 0.970031253194544 / 2.384e-06, + -5.76973e-04 * 0.970031253194544 / 2.384e-06, + -3.4809e-05 * 0.970031253194544 / 2.384e-06, + 2.504869601913055e-01, 1.763842528696710e+00, + + -1.431e-06 * 0.98078528040323 / 2.384e-06, + 9.5367e-05 * 0.98078528040323 / 2.384e-06, + 3.78609e-04 * 0.98078528040323 / 2.384e-06, + -2.161503e-03 * 0.98078528040323 / 2.384e-06, + 3.2754898e-02 * 0.98078528040323 / 2.384e-06, + 4.752159e-03 * 0.98078528040323 / 2.384e-06, + 8.66413e-04 * 0.98078528040323 / 2.384e-06, + 6.2943e-05 * 0.98078528040323 / 2.384e-06, /* 4 */ + 3.815e-06 * 0.98078528040323 / 2.384e-06, + -2.718e-05 * 0.98078528040323 / 2.384e-06, + 5.22137e-04 * 0.98078528040323 / 2.384e-06, + 7.703304e-03 * 0.98078528040323 / 2.384e-06, + -2.7815342e-02 * 0.98078528040323 / 2.384e-06, + -4.290581e-03 * 0.98078528040323 / 2.384e-06, + -6.11782e-04 * 0.98078528040323 / 2.384e-06, + -3.7670e-05 * 0.98078528040323 / 2.384e-06, + 1.989123673796580e-01, 1.847759065022573e+00, + + -1.907e-06 * 0.989176509964781 / 2.384e-06, + 9.0122e-05 * 0.989176509964781 / 2.384e-06, + 2.88486e-04 * 0.989176509964781 / 2.384e-06, + -2.774239e-03 * 0.989176509964781 / 2.384e-06, + 3.2248020e-02 * 0.989176509964781 / 2.384e-06, + 4.748821e-03 * 0.989176509964781 / 2.384e-06, + 8.38757e-04 * 0.989176509964781 / 2.384e-06, + 5.9605e-05 * 0.989176509964781 / 2.384e-06, /* 3 */ + 3.338e-06 * 0.989176509964781 / 2.384e-06, + -3.9577e-05 * 0.989176509964781 / 2.384e-06, + 3.88145e-04 * 0.989176509964781 / 2.384e-06, + 6.937027e-03 * 0.989176509964781 / 2.384e-06, + -2.8532982e-02 * 0.989176509964781 / 2.384e-06, + -4.395962e-03 * 0.989176509964781 / 2.384e-06, + -6.46591e-04 * 0.989176509964781 / 2.384e-06, + -4.0531e-05 * 0.989176509964781 / 2.384e-06, + 1.483359875383474e-01, 1.913880671464418e+00, + + -1.907e-06 * 0.995184726672197 / 2.384e-06, + 8.4400e-05 * 0.995184726672197 / 2.384e-06, + 1.91689e-04 * 0.995184726672197 / 2.384e-06, + -3.411293e-03 * 0.995184726672197 / 2.384e-06, + 3.1706810e-02 * 0.995184726672197 / 2.384e-06, + 4.728317e-03 * 0.995184726672197 / 2.384e-06, + 8.09669e-04 * 0.995184726672197 / 2.384e-06, + 5.579e-05 * 0.995184726672197 / 2.384e-06, + 3.338e-06 * 0.995184726672197 / 2.384e-06, + -5.0545e-05 * 0.995184726672197 / 2.384e-06, + 2.59876e-04 * 0.995184726672197 / 2.384e-06, + 6.189346e-03 * 0.995184726672197 / 2.384e-06, + -2.9224873e-02 * 0.995184726672197 / 2.384e-06, + -4.489899e-03 * 0.995184726672197 / 2.384e-06, + -6.80923e-04 * 0.995184726672197 / 2.384e-06, + -4.3392e-05 * 0.995184726672197 / 2.384e-06, + 9.849140335716425e-02, 1.961570560806461e+00, + + -2.384e-06 * 0.998795456205172 / 2.384e-06, + 7.7724e-05 * 0.998795456205172 / 2.384e-06, + 8.8215e-05 * 0.998795456205172 / 2.384e-06, + -4.072189e-03 * 0.998795456205172 / 2.384e-06, + 3.1132698e-02 * 0.998795456205172 / 2.384e-06, + 4.691124e-03 * 0.998795456205172 / 2.384e-06, + 7.79152e-04 * 0.998795456205172 / 2.384e-06, + 5.2929e-05 * 0.998795456205172 / 2.384e-06, + 2.861e-06 * 0.998795456205172 / 2.384e-06, + -6.0558e-05 * 0.998795456205172 / 2.384e-06, + 1.37329e-04 * 0.998795456205172 / 2.384e-06, + 5.462170e-03 * 0.998795456205172 / 2.384e-06, + -2.9890060e-02 * 0.998795456205172 / 2.384e-06, + -4.570484e-03 * 0.998795456205172 / 2.384e-06, + -7.14302e-04 * 0.998795456205172 / 2.384e-06, + -4.6253e-05 * 0.998795456205172 / 2.384e-06, + 4.912684976946725e-02, 1.990369453344394e+00, + + 3.5780907e-02 * Util.SQRT2 * 0.5 / 2.384e-06, + 1.7876148e-02 * Util.SQRT2 * 0.5 / 2.384e-06, + 3.134727e-03 * Util.SQRT2 * 0.5 / 2.384e-06, + 2.457142e-03 * Util.SQRT2 * 0.5 / 2.384e-06, + 9.71317e-04 * Util.SQRT2 * 0.5 / 2.384e-06, + 2.18868e-04 * Util.SQRT2 * 0.5 / 2.384e-06, + 1.01566e-04 * Util.SQRT2 * 0.5 / 2.384e-06, + 1.3828e-05 * Util.SQRT2 * 0.5 / 2.384e-06, + + 3.0526638e-02 / 2.384e-06, 4.638195e-03 / 2.384e-06, + 7.47204e-04 / 2.384e-06, 4.9591e-05 / 2.384e-06, + 4.756451e-03 / 2.384e-06, 2.1458e-05 / 2.384e-06, + -6.9618e-05 / 2.384e-06, /* 2.384e-06/2.384e-06 */ + ]; + + var NS = 12; + var NL = 36; + + var win = [ + [ + 2.382191739347913e-13, + 6.423305872147834e-13, + 9.400849094049688e-13, + 1.122435026096556e-12, + 1.183840321267481e-12, + 1.122435026096556e-12, + 9.400849094049690e-13, + 6.423305872147839e-13, + 2.382191739347918e-13, + + 5.456116108943412e-12, + 4.878985199565852e-12, + 4.240448995017367e-12, + 3.559909094758252e-12, + 2.858043359288075e-12, + 2.156177623817898e-12, + 1.475637723558783e-12, + 8.371015190102974e-13, + 2.599706096327376e-13, + + -5.456116108943412e-12, + -4.878985199565852e-12, + -4.240448995017367e-12, + -3.559909094758252e-12, + -2.858043359288076e-12, + -2.156177623817898e-12, + -1.475637723558783e-12, + -8.371015190102975e-13, + -2.599706096327376e-13, + + -2.382191739347923e-13, + -6.423305872147843e-13, + -9.400849094049696e-13, + -1.122435026096556e-12, + -1.183840321267481e-12, + -1.122435026096556e-12, + -9.400849094049694e-13, + -6.423305872147840e-13, + -2.382191739347918e-13, + ], + [ + 2.382191739347913e-13, + 6.423305872147834e-13, + 9.400849094049688e-13, + 1.122435026096556e-12, + 1.183840321267481e-12, + 1.122435026096556e-12, + 9.400849094049688e-13, + 6.423305872147841e-13, + 2.382191739347918e-13, + + 5.456116108943413e-12, + 4.878985199565852e-12, + 4.240448995017367e-12, + 3.559909094758253e-12, + 2.858043359288075e-12, + 2.156177623817898e-12, + 1.475637723558782e-12, + 8.371015190102975e-13, + 2.599706096327376e-13, + + -5.461314069809755e-12, + -4.921085770524055e-12, + -4.343405037091838e-12, + -3.732668368707687e-12, + -3.093523840190885e-12, + -2.430835727329465e-12, + -1.734679010007751e-12, + -9.748253656609281e-13, + -2.797435120168326e-13, + + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + -2.283748241799531e-13, + -4.037858874020686e-13, + -2.146547464825323e-13, + ], + [ + 1.316524975873958e-01, /* win[SHORT_TYPE] */ + 4.142135623730950e-01, + 7.673269879789602e-01, + + 1.091308501069271e+00, /* tantab_l */ + 1.303225372841206e+00, + 1.569685577117490e+00, + 1.920982126971166e+00, + 2.414213562373094e+00, + 3.171594802363212e+00, + 4.510708503662055e+00, + 7.595754112725146e+00, + 2.290376554843115e+01, + + 0.98480775301220802032, /* cx */ + 0.64278760968653936292, + 0.34202014332566882393, + 0.93969262078590842791, + -0.17364817766693030343, + -0.76604444311897790243, + 0.86602540378443870761, + 0.500000000000000e+00, + + -5.144957554275265e-01, /* ca */ + -4.717319685649723e-01, + -3.133774542039019e-01, + -1.819131996109812e-01, + -9.457419252642064e-02, + -4.096558288530405e-02, + -1.419856857247115e-02, + -3.699974673760037e-03, + + 8.574929257125442e-01, /* cs */ + 8.817419973177052e-01, + 9.496286491027329e-01, + 9.833145924917901e-01, + 9.955178160675857e-01, + 9.991605581781475e-01, + 9.998991952444470e-01, + 9.999931550702802e-01, + ], + [ + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 2.283748241799531e-13, + 4.037858874020686e-13, + 2.146547464825323e-13, + + 5.461314069809755e-12, + 4.921085770524055e-12, + 4.343405037091838e-12, + 3.732668368707687e-12, + 3.093523840190885e-12, + 2.430835727329466e-12, + 1.734679010007751e-12, + 9.748253656609281e-13, + 2.797435120168326e-13, + + -5.456116108943413e-12, + -4.878985199565852e-12, + -4.240448995017367e-12, + -3.559909094758253e-12, + -2.858043359288075e-12, + -2.156177623817898e-12, + -1.475637723558782e-12, + -8.371015190102975e-13, + -2.599706096327376e-13, + + -2.382191739347913e-13, + -6.423305872147834e-13, + -9.400849094049688e-13, + -1.122435026096556e-12, + -1.183840321267481e-12, + -1.122435026096556e-12, + -9.400849094049688e-13, + -6.423305872147841e-13, + -2.382191739347918e-13, + ] + ]; + + var tantab_l = win[Encoder.SHORT_TYPE]; + var cx = win[Encoder.SHORT_TYPE]; + var ca = win[Encoder.SHORT_TYPE]; + var cs = win[Encoder.SHORT_TYPE]; + + /** + * new IDCT routine written by Takehiro TOMINAGA + * + * PURPOSE: Overlapping window on PCM samples
+ * + * SEMANTICS:
+ * 32 16-bit pcm samples are scaled to fractional 2's complement and + * concatenated to the end of the window buffer #x#. The updated window + * buffer #x# is then windowed by the analysis window #c# to produce the + * windowed sample #z# + */ + var order = [ + 0, 1, 16, 17, 8, 9, 24, 25, 4, 5, 20, 21, 12, 13, 28, 29, + 2, 3, 18, 19, 10, 11, 26, 27, 6, 7, 22, 23, 14, 15, 30, 31 + ]; + + /** + * returns sum_j=0^31 a[j]*cos(PI*j*(k+1/2)/32), 0<=k<32 + */ + function window_subband(x1, x1Pos, a) { + var wp = 10; + + var x2 = x1Pos + 238 - 14 - 286; + + for (var i = -15; i < 0; i++) { + var w, s, t; + + w = enwindow[wp + -10]; + s = x1[x2 + -224] * w; + t = x1[x1Pos + 224] * w; + w = enwindow[wp + -9]; + s += x1[x2 + -160] * w; + t += x1[x1Pos + 160] * w; + w = enwindow[wp + -8]; + s += x1[x2 + -96] * w; + t += x1[x1Pos + 96] * w; + w = enwindow[wp + -7]; + s += x1[x2 + -32] * w; + t += x1[x1Pos + 32] * w; + w = enwindow[wp + -6]; + s += x1[x2 + 32] * w; + t += x1[x1Pos + -32] * w; + w = enwindow[wp + -5]; + s += x1[x2 + 96] * w; + t += x1[x1Pos + -96] * w; + w = enwindow[wp + -4]; + s += x1[x2 + 160] * w; + t += x1[x1Pos + -160] * w; + w = enwindow[wp + -3]; + s += x1[x2 + 224] * w; + t += x1[x1Pos + -224] * w; + + w = enwindow[wp + -2]; + s += x1[x1Pos + -256] * w; + t -= x1[x2 + 256] * w; + w = enwindow[wp + -1]; + s += x1[x1Pos + -192] * w; + t -= x1[x2 + 192] * w; + w = enwindow[wp + 0]; + s += x1[x1Pos + -128] * w; + t -= x1[x2 + 128] * w; + w = enwindow[wp + 1]; + s += x1[x1Pos + -64] * w; + t -= x1[x2 + 64] * w; + w = enwindow[wp + 2]; + s += x1[x1Pos + 0] * w; + t -= x1[x2 + 0] * w; + w = enwindow[wp + 3]; + s += x1[x1Pos + 64] * w; + t -= x1[x2 + -64] * w; + w = enwindow[wp + 4]; + s += x1[x1Pos + 128] * w; + t -= x1[x2 + -128] * w; + w = enwindow[wp + 5]; + s += x1[x1Pos + 192] * w; + t -= x1[x2 + -192] * w; + + /* + * this multiplyer could be removed, but it needs more 256 FLOAT + * data. thinking about the data cache performance, I think we + * should not use such a huge table. tt 2000/Oct/25 + */ + s *= enwindow[wp + 6]; + w = t - s; + a[30 + i * 2] = t + s; + a[31 + i * 2] = enwindow[wp + 7] * w; + wp += 18; + x1Pos--; + x2++; + } + { + var s, t, u, v; + t = x1[x1Pos + -16] * enwindow[wp + -10]; + s = x1[x1Pos + -32] * enwindow[wp + -2]; + t += (x1[x1Pos + -48] - x1[x1Pos + 16]) * enwindow[wp + -9]; + s += x1[x1Pos + -96] * enwindow[wp + -1]; + t += (x1[x1Pos + -80] + x1[x1Pos + 48]) * enwindow[wp + -8]; + s += x1[x1Pos + -160] * enwindow[wp + 0]; + t += (x1[x1Pos + -112] - x1[x1Pos + 80]) * enwindow[wp + -7]; + s += x1[x1Pos + -224] * enwindow[wp + 1]; + t += (x1[x1Pos + -144] + x1[x1Pos + 112]) * enwindow[wp + -6]; + s -= x1[x1Pos + 32] * enwindow[wp + 2]; + t += (x1[x1Pos + -176] - x1[x1Pos + 144]) * enwindow[wp + -5]; + s -= x1[x1Pos + 96] * enwindow[wp + 3]; + t += (x1[x1Pos + -208] + x1[x1Pos + 176]) * enwindow[wp + -4]; + s -= x1[x1Pos + 160] * enwindow[wp + 4]; + t += (x1[x1Pos + -240] - x1[x1Pos + 208]) * enwindow[wp + -3]; + s -= x1[x1Pos + 224]; + + u = s - t; + v = s + t; + + t = a[14]; + s = a[15] - t; + + a[31] = v + t; /* A0 */ + a[30] = u + s; /* A1 */ + a[15] = u - s; /* A2 */ + a[14] = v - t; /* A3 */ + } + { + var xr; + xr = a[28] - a[0]; + a[0] += a[28]; + a[28] = xr * enwindow[wp + -2 * 18 + 7]; + xr = a[29] - a[1]; + a[1] += a[29]; + a[29] = xr * enwindow[wp + -2 * 18 + 7]; + + xr = a[26] - a[2]; + a[2] += a[26]; + a[26] = xr * enwindow[wp + -4 * 18 + 7]; + xr = a[27] - a[3]; + a[3] += a[27]; + a[27] = xr * enwindow[wp + -4 * 18 + 7]; + + xr = a[24] - a[4]; + a[4] += a[24]; + a[24] = xr * enwindow[wp + -6 * 18 + 7]; + xr = a[25] - a[5]; + a[5] += a[25]; + a[25] = xr * enwindow[wp + -6 * 18 + 7]; + + xr = a[22] - a[6]; + a[6] += a[22]; + a[22] = xr * Util.SQRT2; + xr = a[23] - a[7]; + a[7] += a[23]; + a[23] = xr * Util.SQRT2 - a[7]; + a[7] -= a[6]; + a[22] -= a[7]; + a[23] -= a[22]; + + xr = a[6]; + a[6] = a[31] - xr; + a[31] = a[31] + xr; + xr = a[7]; + a[7] = a[30] - xr; + a[30] = a[30] + xr; + xr = a[22]; + a[22] = a[15] - xr; + a[15] = a[15] + xr; + xr = a[23]; + a[23] = a[14] - xr; + a[14] = a[14] + xr; + + xr = a[20] - a[8]; + a[8] += a[20]; + a[20] = xr * enwindow[wp + -10 * 18 + 7]; + xr = a[21] - a[9]; + a[9] += a[21]; + a[21] = xr * enwindow[wp + -10 * 18 + 7]; + + xr = a[18] - a[10]; + a[10] += a[18]; + a[18] = xr * enwindow[wp + -12 * 18 + 7]; + xr = a[19] - a[11]; + a[11] += a[19]; + a[19] = xr * enwindow[wp + -12 * 18 + 7]; + + xr = a[16] - a[12]; + a[12] += a[16]; + a[16] = xr * enwindow[wp + -14 * 18 + 7]; + xr = a[17] - a[13]; + a[13] += a[17]; + a[17] = xr * enwindow[wp + -14 * 18 + 7]; + + xr = -a[20] + a[24]; + a[20] += a[24]; + a[24] = xr * enwindow[wp + -12 * 18 + 7]; + xr = -a[21] + a[25]; + a[21] += a[25]; + a[25] = xr * enwindow[wp + -12 * 18 + 7]; + + xr = a[4] - a[8]; + a[4] += a[8]; + a[8] = xr * enwindow[wp + -12 * 18 + 7]; + xr = a[5] - a[9]; + a[5] += a[9]; + a[9] = xr * enwindow[wp + -12 * 18 + 7]; + + xr = a[0] - a[12]; + a[0] += a[12]; + a[12] = xr * enwindow[wp + -4 * 18 + 7]; + xr = a[1] - a[13]; + a[1] += a[13]; + a[13] = xr * enwindow[wp + -4 * 18 + 7]; + xr = a[16] - a[28]; + a[16] += a[28]; + a[28] = xr * enwindow[wp + -4 * 18 + 7]; + xr = -a[17] + a[29]; + a[17] += a[29]; + a[29] = xr * enwindow[wp + -4 * 18 + 7]; + + xr = Util.SQRT2 * (a[2] - a[10]); + a[2] += a[10]; + a[10] = xr; + xr = Util.SQRT2 * (a[3] - a[11]); + a[3] += a[11]; + a[11] = xr; + xr = Util.SQRT2 * (-a[18] + a[26]); + a[18] += a[26]; + a[26] = xr - a[18]; + xr = Util.SQRT2 * (-a[19] + a[27]); + a[19] += a[27]; + a[27] = xr - a[19]; + + xr = a[2]; + a[19] -= a[3]; + a[3] -= xr; + a[2] = a[31] - xr; + a[31] += xr; + xr = a[3]; + a[11] -= a[19]; + a[18] -= xr; + a[3] = a[30] - xr; + a[30] += xr; + xr = a[18]; + a[27] -= a[11]; + a[19] -= xr; + a[18] = a[15] - xr; + a[15] += xr; + + xr = a[19]; + a[10] -= xr; + a[19] = a[14] - xr; + a[14] += xr; + xr = a[10]; + a[11] -= xr; + a[10] = a[23] - xr; + a[23] += xr; + xr = a[11]; + a[26] -= xr; + a[11] = a[22] - xr; + a[22] += xr; + xr = a[26]; + a[27] -= xr; + a[26] = a[7] - xr; + a[7] += xr; + + xr = a[27]; + a[27] = a[6] - xr; + a[6] += xr; + + xr = Util.SQRT2 * (a[0] - a[4]); + a[0] += a[4]; + a[4] = xr; + xr = Util.SQRT2 * (a[1] - a[5]); + a[1] += a[5]; + a[5] = xr; + xr = Util.SQRT2 * (a[16] - a[20]); + a[16] += a[20]; + a[20] = xr; + xr = Util.SQRT2 * (a[17] - a[21]); + a[17] += a[21]; + a[21] = xr; + + xr = -Util.SQRT2 * (a[8] - a[12]); + a[8] += a[12]; + a[12] = xr - a[8]; + xr = -Util.SQRT2 * (a[9] - a[13]); + a[9] += a[13]; + a[13] = xr - a[9]; + xr = -Util.SQRT2 * (a[25] - a[29]); + a[25] += a[29]; + a[29] = xr - a[25]; + xr = -Util.SQRT2 * (a[24] + a[28]); + a[24] -= a[28]; + a[28] = xr - a[24]; + + xr = a[24] - a[16]; + a[24] = xr; + xr = a[20] - xr; + a[20] = xr; + xr = a[28] - xr; + a[28] = xr; + + xr = a[25] - a[17]; + a[25] = xr; + xr = a[21] - xr; + a[21] = xr; + xr = a[29] - xr; + a[29] = xr; + + xr = a[17] - a[1]; + a[17] = xr; + xr = a[9] - xr; + a[9] = xr; + xr = a[25] - xr; + a[25] = xr; + xr = a[5] - xr; + a[5] = xr; + xr = a[21] - xr; + a[21] = xr; + xr = a[13] - xr; + a[13] = xr; + xr = a[29] - xr; + a[29] = xr; + + xr = a[1] - a[0]; + a[1] = xr; + xr = a[16] - xr; + a[16] = xr; + xr = a[17] - xr; + a[17] = xr; + xr = a[8] - xr; + a[8] = xr; + xr = a[9] - xr; + a[9] = xr; + xr = a[24] - xr; + a[24] = xr; + xr = a[25] - xr; + a[25] = xr; + xr = a[4] - xr; + a[4] = xr; + xr = a[5] - xr; + a[5] = xr; + xr = a[20] - xr; + a[20] = xr; + xr = a[21] - xr; + a[21] = xr; + xr = a[12] - xr; + a[12] = xr; + xr = a[13] - xr; + a[13] = xr; + xr = a[28] - xr; + a[28] = xr; + xr = a[29] - xr; + a[29] = xr; + + xr = a[0]; + a[0] += a[31]; + a[31] -= xr; + xr = a[1]; + a[1] += a[30]; + a[30] -= xr; + xr = a[16]; + a[16] += a[15]; + a[15] -= xr; + xr = a[17]; + a[17] += a[14]; + a[14] -= xr; + xr = a[8]; + a[8] += a[23]; + a[23] -= xr; + xr = a[9]; + a[9] += a[22]; + a[22] -= xr; + xr = a[24]; + a[24] += a[7]; + a[7] -= xr; + xr = a[25]; + a[25] += a[6]; + a[6] -= xr; + xr = a[4]; + a[4] += a[27]; + a[27] -= xr; + xr = a[5]; + a[5] += a[26]; + a[26] -= xr; + xr = a[20]; + a[20] += a[11]; + a[11] -= xr; + xr = a[21]; + a[21] += a[10]; + a[10] -= xr; + xr = a[12]; + a[12] += a[19]; + a[19] -= xr; + xr = a[13]; + a[13] += a[18]; + a[18] -= xr; + xr = a[28]; + a[28] += a[3]; + a[3] -= xr; + xr = a[29]; + a[29] += a[2]; + a[2] -= xr; + } + } + + /** + * Function: Calculation of the MDCT In the case of long blocks (type 0,1,3) + * there are 36 coefficents in the time domain and 18 in the frequency + * domain.
+ * In the case of short blocks (type 2) there are 3 transformations with + * short length. This leads to 12 coefficents in the time and 6 in the + * frequency domain. In this case the results are stored side by side in the + * vector out[]. + * + * New layer3 + */ + function mdct_short(inout, inoutPos) { + for (var l = 0; l < 3; l++) { + var tc0, tc1, tc2, ts0, ts1, ts2; + + ts0 = inout[inoutPos + 2 * 3] * win[Encoder.SHORT_TYPE][0] + - inout[inoutPos + 5 * 3]; + tc0 = inout[inoutPos + 0 * 3] * win[Encoder.SHORT_TYPE][2] + - inout[inoutPos + 3 * 3]; + tc1 = ts0 + tc0; + tc2 = ts0 - tc0; + + ts0 = inout[inoutPos + 5 * 3] * win[Encoder.SHORT_TYPE][0] + + inout[inoutPos + 2 * 3]; + tc0 = inout[inoutPos + 3 * 3] * win[Encoder.SHORT_TYPE][2] + + inout[inoutPos + 0 * 3]; + ts1 = ts0 + tc0; + ts2 = -ts0 + tc0; + + tc0 = (inout[inoutPos + 1 * 3] * win[Encoder.SHORT_TYPE][1] - inout[inoutPos + 4 * 3]) * 2.069978111953089e-11; + /* + * tritab_s [ 1 ] + */ + ts0 = (inout[inoutPos + 4 * 3] * win[Encoder.SHORT_TYPE][1] + inout[inoutPos + 1 * 3]) * 2.069978111953089e-11; + /* + * tritab_s [ 1 ] + */ + inout[inoutPos + 3 * 0] = tc1 * 1.907525191737280e-11 + tc0; + /* + * tritab_s[ 2 ] + */ + inout[inoutPos + 3 * 5] = -ts1 * 1.907525191737280e-11 + ts0; + /* + * tritab_s[0 ] + */ + tc2 = tc2 * 0.86602540378443870761 * 1.907525191737281e-11; + /* + * tritab_s[ 2] + */ + ts1 = ts1 * 0.5 * 1.907525191737281e-11 + ts0; + inout[inoutPos + 3 * 1] = tc2 - ts1; + inout[inoutPos + 3 * 2] = tc2 + ts1; + + tc1 = tc1 * 0.5 * 1.907525191737281e-11 - tc0; + ts2 = ts2 * 0.86602540378443870761 * 1.907525191737281e-11; + /* + * tritab_s[ 0] + */ + inout[inoutPos + 3 * 3] = tc1 + ts2; + inout[inoutPos + 3 * 4] = tc1 - ts2; + + inoutPos++; + } + } + + function mdct_long(out, outPos, _in) { + var ct, st; + { + var tc1, tc2, tc3, tc4, ts5, ts6, ts7, ts8; + /* 1,2, 5,6, 9,10, 13,14, 17 */ + tc1 = _in[17] - _in[9]; + tc3 = _in[15] - _in[11]; + tc4 = _in[14] - _in[12]; + ts5 = _in[0] + _in[8]; + ts6 = _in[1] + _in[7]; + ts7 = _in[2] + _in[6]; + ts8 = _in[3] + _in[5]; + + out[outPos + 17] = (ts5 + ts7 - ts8) - (ts6 - _in[4]); + st = (ts5 + ts7 - ts8) * cx[12 + 7] + (ts6 - _in[4]); + ct = (tc1 - tc3 - tc4) * cx[12 + 6]; + out[outPos + 5] = ct + st; + out[outPos + 6] = ct - st; + + tc2 = (_in[16] - _in[10]) * cx[12 + 6]; + ts6 = ts6 * cx[12 + 7] + _in[4]; + ct = tc1 * cx[12 + 0] + tc2 + tc3 * cx[12 + 1] + tc4 * cx[12 + 2]; + st = -ts5 * cx[12 + 4] + ts6 - ts7 * cx[12 + 5] + ts8 * cx[12 + 3]; + out[outPos + 1] = ct + st; + out[outPos + 2] = ct - st; + + ct = tc1 * cx[12 + 1] - tc2 - tc3 * cx[12 + 2] + tc4 * cx[12 + 0]; + st = -ts5 * cx[12 + 5] + ts6 - ts7 * cx[12 + 3] + ts8 * cx[12 + 4]; + out[outPos + 9] = ct + st; + out[outPos + 10] = ct - st; + + ct = tc1 * cx[12 + 2] - tc2 + tc3 * cx[12 + 0] - tc4 * cx[12 + 1]; + st = ts5 * cx[12 + 3] - ts6 + ts7 * cx[12 + 4] - ts8 * cx[12 + 5]; + out[outPos + 13] = ct + st; + out[outPos + 14] = ct - st; + } + { + var ts1, ts2, ts3, ts4, tc5, tc6, tc7, tc8; + + ts1 = _in[8] - _in[0]; + ts3 = _in[6] - _in[2]; + ts4 = _in[5] - _in[3]; + tc5 = _in[17] + _in[9]; + tc6 = _in[16] + _in[10]; + tc7 = _in[15] + _in[11]; + tc8 = _in[14] + _in[12]; + + out[outPos + 0] = (tc5 + tc7 + tc8) + (tc6 + _in[13]); + ct = (tc5 + tc7 + tc8) * cx[12 + 7] - (tc6 + _in[13]); + st = (ts1 - ts3 + ts4) * cx[12 + 6]; + out[outPos + 11] = ct + st; + out[outPos + 12] = ct - st; + + ts2 = (_in[7] - _in[1]) * cx[12 + 6]; + tc6 = _in[13] - tc6 * cx[12 + 7]; + ct = tc5 * cx[12 + 3] - tc6 + tc7 * cx[12 + 4] + tc8 * cx[12 + 5]; + st = ts1 * cx[12 + 2] + ts2 + ts3 * cx[12 + 0] + ts4 * cx[12 + 1]; + out[outPos + 3] = ct + st; + out[outPos + 4] = ct - st; + + ct = -tc5 * cx[12 + 5] + tc6 - tc7 * cx[12 + 3] - tc8 * cx[12 + 4]; + st = ts1 * cx[12 + 1] + ts2 - ts3 * cx[12 + 2] - ts4 * cx[12 + 0]; + out[outPos + 7] = ct + st; + out[outPos + 8] = ct - st; + + ct = -tc5 * cx[12 + 4] + tc6 - tc7 * cx[12 + 5] - tc8 * cx[12 + 3]; + st = ts1 * cx[12 + 0] - ts2 + ts3 * cx[12 + 1] - ts4 * cx[12 + 2]; + out[outPos + 15] = ct + st; + out[outPos + 16] = ct - st; + } + } + + this.mdct_sub48 = function(gfc, w0, w1) { + var wk = w0; + var wkPos = 286; + /* thinking cache performance, ch->gr loop is better than gr->ch loop */ + for (var ch = 0; ch < gfc.channels_out; ch++) { + for (var gr = 0; gr < gfc.mode_gr; gr++) { + var band; + var gi = (gfc.l3_side.tt[gr][ch]); + var mdct_enc = gi.xr; + var mdct_encPos = 0; + var samp = gfc.sb_sample[ch][1 - gr]; + var sampPos = 0; + + for (var k = 0; k < 18 / 2; k++) { + window_subband(wk, wkPos, samp[sampPos]); + window_subband(wk, wkPos + 32, samp[sampPos + 1]); + sampPos += 2; + wkPos += 64; + /* + * Compensate for inversion in the analysis filter + */ + for (band = 1; band < 32; band += 2) { + samp[sampPos - 1][band] *= -1; + } + } + + /* + * Perform imdct of 18 previous subband samples + 18 current + * subband samples + */ + for (band = 0; band < 32; band++, mdct_encPos += 18) { + var type = gi.block_type; + var band0 = gfc.sb_sample[ch][gr]; + var band1 = gfc.sb_sample[ch][1 - gr]; + if (gi.mixed_block_flag != 0 && band < 2) + type = 0; + if (gfc.amp_filter[band] < 1e-12) { + Arrays.fill(mdct_enc, mdct_encPos + 0, + mdct_encPos + 18, 0); + } else { + if (gfc.amp_filter[band] < 1.0) { + for (var k = 0; k < 18; k++) + band1[k][order[band]] *= gfc.amp_filter[band]; + } + if (type == Encoder.SHORT_TYPE) { + for (var k = -NS / 4; k < 0; k++) { + var w = win[Encoder.SHORT_TYPE][k + 3]; + mdct_enc[mdct_encPos + k * 3 + 9] = band0[9 + k][order[band]] + * w - band0[8 - k][order[band]]; + mdct_enc[mdct_encPos + k * 3 + 18] = band0[14 - k][order[band]] + * w + band0[15 + k][order[band]]; + mdct_enc[mdct_encPos + k * 3 + 10] = band0[15 + k][order[band]] + * w - band0[14 - k][order[band]]; + mdct_enc[mdct_encPos + k * 3 + 19] = band1[2 - k][order[band]] + * w + band1[3 + k][order[band]]; + mdct_enc[mdct_encPos + k * 3 + 11] = band1[3 + k][order[band]] + * w - band1[2 - k][order[band]]; + mdct_enc[mdct_encPos + k * 3 + 20] = band1[8 - k][order[band]] + * w + band1[9 + k][order[band]]; + } + mdct_short(mdct_enc, mdct_encPos); + } else { + var work = new_float(18); + for (var k = -NL / 4; k < 0; k++) { + var a, b; + a = win[type][k + 27] + * band1[k + 9][order[band]] + + win[type][k + 36] + * band1[8 - k][order[band]]; + b = win[type][k + 9] + * band0[k + 9][order[band]] + - win[type][k + 18] + * band0[8 - k][order[band]]; + work[k + 9] = a - b * tantab_l[3 + k + 9]; + work[k + 18] = a * tantab_l[3 + k + 9] + b; + } + + mdct_long(mdct_enc, mdct_encPos, work); + } + } + /* + * Perform aliasing reduction butterfly + */ + if (type != Encoder.SHORT_TYPE && band != 0) { + for (var k = 7; k >= 0; --k) { + var bu, bd; + bu = mdct_enc[mdct_encPos + k] * ca[20 + k] + + mdct_enc[mdct_encPos + -1 - k] + * cs[28 + k]; + bd = mdct_enc[mdct_encPos + k] * cs[28 + k] + - mdct_enc[mdct_encPos + -1 - k] + * ca[20 + k]; + + mdct_enc[mdct_encPos + -1 - k] = bu; + mdct_enc[mdct_encPos + k] = bd; + } + } + } + } + wk = w1; + wkPos = 286; + if (gfc.mode_gr == 1) { + for (var i = 0; i < 18; i++) { + System.arraycopy(gfc.sb_sample[ch][1][i], 0, + gfc.sb_sample[ch][0][i], 0, 32); + } + } + } + } +} + +//package mp3; + + +function III_psy_ratio() { + this.thm = new III_psy_xmin(); + this.en = new III_psy_xmin(); +} + + +/** + * ENCDELAY The encoder delay. + * + * Minimum allowed is MDCTDELAY (see below) + * + * The first 96 samples will be attenuated, so using a value less than 96 + * will result in corrupt data for the first 96-ENCDELAY samples. + * + * suggested: 576 set to 1160 to sync with FhG. + */ +Encoder.ENCDELAY = 576; +/** + * make sure there is at least one complete frame after the last frame + * containing real data + * + * Using a value of 288 would be sufficient for a a very sophisticated + * decoder that can decode granule-by-granule instead of frame by frame. But + * lets not assume this, and assume the decoder will not decode frame N + * unless it also has data for frame N+1 + */ +Encoder.POSTDELAY = 1152; + +/** + * delay of the MDCT used in mdct.c original ISO routines had a delay of + * 528! Takehiro's routines: + */ +Encoder.MDCTDELAY = 48; +Encoder.FFTOFFSET = (224 + Encoder.MDCTDELAY); + +/** + * Most decoders, including the one we use, have a delay of 528 samples. + */ +Encoder.DECDELAY = 528; + +/** + * number of subbands + */ +Encoder.SBLIMIT = 32; + +/** + * parition bands bands + */ +Encoder.CBANDS = 64; + +/** + * number of critical bands/scale factor bands where masking is computed + */ +Encoder.SBPSY_l = 21; +Encoder.SBPSY_s = 12; + +/** + * total number of scalefactor bands encoded + */ +Encoder.SBMAX_l = 22; +Encoder.SBMAX_s = 13; +Encoder.PSFB21 = 6; +Encoder.PSFB12 = 6; + +/** + * FFT sizes + */ +Encoder.BLKSIZE = 1024; +Encoder.HBLKSIZE = (Encoder.BLKSIZE / 2 + 1); +Encoder.BLKSIZE_s = 256; +Encoder.HBLKSIZE_s = (Encoder.BLKSIZE_s / 2 + 1); + +Encoder.NORM_TYPE = 0; +Encoder.START_TYPE = 1; +Encoder.SHORT_TYPE = 2; +Encoder.STOP_TYPE = 3; + +/** + *
+ * Mode Extention:
+ * When we are in stereo mode, there are 4 possible methods to store these
+ * two channels. The stereo modes -m? are using a subset of them.
+ *
+ *  -ms: MPG_MD_LR_LR
+ *  -mj: MPG_MD_LR_LR and MPG_MD_MS_LR
+ *  -mf: MPG_MD_MS_LR
+ *  -mi: all
+ * 
+ */ +Encoder.MPG_MD_LR_LR = 0; +Encoder.MPG_MD_LR_I = 1; +Encoder.MPG_MD_MS_LR = 2; +Encoder.MPG_MD_MS_I = 3; + +Encoder.fircoef = [-0.0207887 * 5, -0.0378413 * 5, + -0.0432472 * 5, -0.031183 * 5, 7.79609e-18 * 5, 0.0467745 * 5, + 0.10091 * 5, 0.151365 * 5, 0.187098 * 5]; + +function Encoder() { + + var FFTOFFSET = Encoder.FFTOFFSET; + var MPG_MD_MS_LR = Encoder.MPG_MD_MS_LR; + //BitStream bs; + //PsyModel psy; + //VBRTag vbr; + //QuantizePVT qupvt; + var bs = null; + this.psy = null; + var psy = null; + var vbr = null; + var qupvt = null; + + //public final void setModules(BitStream bs, PsyModel psy, QuantizePVT qupvt, + // VBRTag vbr) { + this.setModules = function (_bs, _psy, _qupvt, _vbr) { + bs = _bs; + this.psy = _psy; + psy = _psy; + vbr = _vbr; + qupvt = _qupvt; + }; + + var newMDCT = new NewMDCT(); + + /*********************************************************************** + * + * encoder and decoder delays + * + ***********************************************************************/ + + /** + *
+     * layer III enc->dec delay:  1056 (1057?)   (observed)
+     * layer  II enc->dec delay:   480  (481?)   (observed)
+     *
+     * polyphase 256-16             (dec or enc)        = 240
+     * mdct      256+32  (9*32)     (dec or enc)        = 288
+     * total:    512+16
+     *
+     * My guess is that delay of polyphase filterbank is actualy 240.5
+     * (there are technical reasons for this, see postings in mp3encoder).
+     * So total Encode+Decode delay = ENCDELAY + 528 + 1
+     * 
+ */ + + + /** + * auto-adjust of ATH, useful for low volume Gabriel Bouvigne 3 feb 2001 + * + * modifies some values in gfp.internal_flags.ATH (gfc.ATH) + */ +//private void adjust_ATH(final LameInternalFlags gfc) { + function adjust_ATH(gfc) { + var gr2_max, max_pow; + + if (gfc.ATH.useAdjust == 0) { + gfc.ATH.adjust = 1.0; + /* no adjustment */ + return; + } + + /* jd - 2001 mar 12, 27, jun 30 */ + /* loudness based on equal loudness curve; */ + /* use granule with maximum combined loudness */ + max_pow = gfc.loudness_sq[0][0]; + gr2_max = gfc.loudness_sq[1][0]; + if (gfc.channels_out == 2) { + max_pow += gfc.loudness_sq[0][1]; + gr2_max += gfc.loudness_sq[1][1]; + } else { + max_pow += max_pow; + gr2_max += gr2_max; + } + if (gfc.mode_gr == 2) { + max_pow = Math.max(max_pow, gr2_max); + } + max_pow *= 0.5; + /* max_pow approaches 1.0 for full band noise */ + + /* jd - 2001 mar 31, jun 30 */ + /* user tuning of ATH adjustment region */ + max_pow *= gfc.ATH.aaSensitivityP; + + /* + * adjust ATH depending on range of maximum value + */ + + /* jd - 2001 feb27, mar12,20, jun30, jul22 */ + /* continuous curves based on approximation */ + /* to GB's original values. */ + /* For an increase in approximate loudness, */ + /* set ATH adjust to adjust_limit immediately */ + /* after a delay of one frame. */ + /* For a loudness decrease, reduce ATH adjust */ + /* towards adjust_limit gradually. */ + /* max_pow is a loudness squared or a power. */ + if (max_pow > 0.03125) { /* ((1 - 0.000625)/ 31.98) from curve below */ + if (gfc.ATH.adjust >= 1.0) { + gfc.ATH.adjust = 1.0; + } else { + /* preceding frame has lower ATH adjust; */ + /* ascend only to the preceding adjust_limit */ + /* in case there is leading low volume */ + if (gfc.ATH.adjust < gfc.ATH.adjustLimit) { + gfc.ATH.adjust = gfc.ATH.adjustLimit; + } + } + gfc.ATH.adjustLimit = 1.0; + } else { /* adjustment curve */ + /* about 32 dB maximum adjust (0.000625) */ + var adj_lim_new = 31.98 * max_pow + 0.000625; + if (gfc.ATH.adjust >= adj_lim_new) { /* descend gradually */ + gfc.ATH.adjust *= adj_lim_new * 0.075 + 0.925; + if (gfc.ATH.adjust < adj_lim_new) { /* stop descent */ + gfc.ATH.adjust = adj_lim_new; + } + } else { /* ascend */ + if (gfc.ATH.adjustLimit >= adj_lim_new) { + gfc.ATH.adjust = adj_lim_new; + } else { + /* preceding frame has lower ATH adjust; */ + /* ascend only to the preceding adjust_limit */ + if (gfc.ATH.adjust < gfc.ATH.adjustLimit) { + gfc.ATH.adjust = gfc.ATH.adjustLimit; + } + } + } + gfc.ATH.adjustLimit = adj_lim_new; + } + } + + /** + *
+     *  some simple statistics
+     *
+     *  bitrate index 0: free bitrate . not allowed in VBR mode
+     *  : bitrates, kbps depending on MPEG version
+     *  bitrate index 15: forbidden
+     *
+     *  mode_ext:
+     *  0:  LR
+     *  1:  LR-i
+     *  2:  MS
+     *  3:  MS-i
+     * 
+ */ + function updateStats(gfc) { + var gr, ch; + + /* count bitrate indices */ + gfc.bitrate_stereoMode_Hist[gfc.bitrate_index][4]++; + gfc.bitrate_stereoMode_Hist[15][4]++; + + /* count 'em for every mode extension in case of 2 channel encoding */ + if (gfc.channels_out == 2) { + gfc.bitrate_stereoMode_Hist[gfc.bitrate_index][gfc.mode_ext]++; + gfc.bitrate_stereoMode_Hist[15][gfc.mode_ext]++; + } + for (gr = 0; gr < gfc.mode_gr; ++gr) { + for (ch = 0; ch < gfc.channels_out; ++ch) { + var bt = gfc.l3_side.tt[gr][ch].block_type | 0; + if (gfc.l3_side.tt[gr][ch].mixed_block_flag != 0) + bt = 4; + gfc.bitrate_blockType_Hist[gfc.bitrate_index][bt]++; + gfc.bitrate_blockType_Hist[gfc.bitrate_index][5]++; + gfc.bitrate_blockType_Hist[15][bt]++; + gfc.bitrate_blockType_Hist[15][5]++; + } + } + } + + function lame_encode_frame_init(gfp, inbuf) { + var gfc = gfp.internal_flags; + + var ch, gr; + + if (gfc.lame_encode_frame_init == 0) { + /* prime the MDCT/polyphase filterbank with a short block */ + var i, j; + var primebuff0 = new_float(286 + 1152 + 576); + var primebuff1 = new_float(286 + 1152 + 576); + gfc.lame_encode_frame_init = 1; + for (i = 0, j = 0; i < 286 + 576 * (1 + gfc.mode_gr); ++i) { + if (i < 576 * gfc.mode_gr) { + primebuff0[i] = 0; + if (gfc.channels_out == 2) + primebuff1[i] = 0; + } else { + primebuff0[i] = inbuf[0][j]; + if (gfc.channels_out == 2) + primebuff1[i] = inbuf[1][j]; + ++j; + } + } + /* polyphase filtering / mdct */ + for (gr = 0; gr < gfc.mode_gr; gr++) { + for (ch = 0; ch < gfc.channels_out; ch++) { + gfc.l3_side.tt[gr][ch].block_type = Encoder.SHORT_TYPE; + } + } + newMDCT.mdct_sub48(gfc, primebuff0, primebuff1); + + /* check FFT will not use a negative starting offset */ + /* check if we have enough data for FFT */ + /* check if we have enough data for polyphase filterbank */ + } + + } + + /** + *
+     * encodeframe()           Layer 3
+     *
+     * encode a single frame
+     *
+     *
+     *    lame_encode_frame()
+     *
+     *
+     *                           gr 0            gr 1
+     *    inbuf:           |--------------|--------------|--------------|
+     *
+     *
+     *    Polyphase (18 windows, each shifted 32)
+     *    gr 0:
+     *    window1          <----512---.
+     *    window18                 <----512---.
+     *
+     *    gr 1:
+     *    window1                         <----512---.
+     *    window18                                <----512---.
+     *
+     *
+     *
+     *    MDCT output:  |--------------|--------------|--------------|
+     *
+     *    FFT's                    <---------1024---------.
+     *                                             <---------1024-------.
+     *
+     *
+     *
+     *        inbuf = buffer of PCM data size=MP3 framesize
+     *        encoder acts on inbuf[ch][0], but output is delayed by MDCTDELAY
+     *        so the MDCT coefficints are from inbuf[ch][-MDCTDELAY]
+     *
+     *        psy-model FFT has a 1 granule delay, so we feed it data for the
+     *        next granule.
+     *        FFT is centered over granule:  224+576+224
+     *        So FFT starts at:   576-224-MDCTDELAY
+     *
+     *        MPEG2:  FFT ends at:  BLKSIZE+576-224-MDCTDELAY      (1328)
+     *        MPEG1:  FFT ends at:  BLKSIZE+2*576-224-MDCTDELAY    (1904)
+     *
+     *        MPEG2:  polyphase first window:  [0..511]
+     *                          18th window:   [544..1055]          (1056)
+     *        MPEG1:            36th window:   [1120..1631]         (1632)
+     *                data needed:  512+framesize-32
+     *
+     *        A close look newmdct.c shows that the polyphase filterbank
+     *        only uses data from [0..510] for each window.  Perhaps because the window
+     *        used by the filterbank is zero for the last point, so Takehiro's
+     *        code doesn't bother to compute with it.
+     *
+     *        FFT starts at 576-224-MDCTDELAY (304)  = 576-FFTOFFSET
+     *
+     * 
+ */ + + + this.lame_encode_mp3_frame = function (gfp, inbuf_l, inbuf_r, mp3buf, mp3bufPos, mp3buf_size) { + var mp3count; + var masking_LR = new_array_n([2, 2]); + /* + * LR masking & + * energy + */ + masking_LR[0][0] = new III_psy_ratio(); + masking_LR[0][1] = new III_psy_ratio(); + masking_LR[1][0] = new III_psy_ratio(); + masking_LR[1][1] = new III_psy_ratio(); + var masking_MS = new_array_n([2, 2]); + /* MS masking & energy */ + masking_MS[0][0] = new III_psy_ratio(); + masking_MS[0][1] = new III_psy_ratio(); + masking_MS[1][0] = new III_psy_ratio(); + masking_MS[1][1] = new III_psy_ratio(); + //III_psy_ratio masking[][]; + var masking; + /* pointer to selected maskings */ + var inbuf = [null, null]; + var gfc = gfp.internal_flags; + + var tot_ener = new_float_n([2, 4]); + var ms_ener_ratio = [.5, .5]; + var pe = [[0., 0.], [0., 0.]]; + var pe_MS = [[0., 0.], [0., 0.]]; + +//float[][] pe_use; + var pe_use; + + var ch, gr; + + inbuf[0] = inbuf_l; + inbuf[1] = inbuf_r; + + if (gfc.lame_encode_frame_init == 0) { + /* first run? */ + lame_encode_frame_init(gfp, inbuf); + + } + + /********************** padding *****************************/ + /** + *
+         * padding method as described in
+         * "MPEG-Layer3 / Bitstream Syntax and Decoding"
+         * by Martin Sieler, Ralph Sperschneider
+         *
+         * note: there is no padding for the very first frame
+         *
+         * Robert Hegemann 2000-06-22
+         * 
+ */ + gfc.padding = 0; + if ((gfc.slot_lag -= gfc.frac_SpF) < 0) { + gfc.slot_lag += gfp.out_samplerate; + gfc.padding = 1; + } + + /**************************************** + * Stage 1: psychoacoustic model * + ****************************************/ + + if (gfc.psymodel != 0) { + /* + * psychoacoustic model psy model has a 1 granule (576) delay that + * we must compensate for (mt 6/99). + */ + var ret; + var bufp = [null, null]; + /* address of beginning of left & right granule */ + var bufpPos = 0; + /* address of beginning of left & right granule */ + var blocktype = new_int(2); + + for (gr = 0; gr < gfc.mode_gr; gr++) { + + for (ch = 0; ch < gfc.channels_out; ch++) { + bufp[ch] = inbuf[ch]; + bufpPos = 576 + gr * 576 - Encoder.FFTOFFSET; + } + if (gfp.VBR == VbrMode.vbr_mtrh || gfp.VBR == VbrMode.vbr_mt) { + ret = psy.L3psycho_anal_vbr(gfp, bufp, bufpPos, gr, + masking_LR, masking_MS, pe[gr], pe_MS[gr], + tot_ener[gr], blocktype); + } else { + ret = psy.L3psycho_anal_ns(gfp, bufp, bufpPos, gr, + masking_LR, masking_MS, pe[gr], pe_MS[gr], + tot_ener[gr], blocktype); + } + if (ret != 0) + return -4; + + if (gfp.mode == MPEGMode.JOINT_STEREO) { + ms_ener_ratio[gr] = tot_ener[gr][2] + tot_ener[gr][3]; + if (ms_ener_ratio[gr] > 0) + ms_ener_ratio[gr] = tot_ener[gr][3] / ms_ener_ratio[gr]; + } + + /* block type flags */ + for (ch = 0; ch < gfc.channels_out; ch++) { + var cod_info = gfc.l3_side.tt[gr][ch]; + cod_info.block_type = blocktype[ch]; + cod_info.mixed_block_flag = 0; + } + } + } else { + /* no psy model */ + for (gr = 0; gr < gfc.mode_gr; gr++) + for (ch = 0; ch < gfc.channels_out; ch++) { + gfc.l3_side.tt[gr][ch].block_type = Encoder.NORM_TYPE; + gfc.l3_side.tt[gr][ch].mixed_block_flag = 0; + pe_MS[gr][ch] = pe[gr][ch] = 700; + } + } + + /* auto-adjust of ATH, useful for low volume */ + adjust_ATH(gfc); + + /**************************************** + * Stage 2: MDCT * + ****************************************/ + + /* polyphase filtering / mdct */ + newMDCT.mdct_sub48(gfc, inbuf[0], inbuf[1]); + + /**************************************** + * Stage 3: MS/LR decision * + ****************************************/ + + /* Here will be selected MS or LR coding of the 2 stereo channels */ + gfc.mode_ext = Encoder.MPG_MD_LR_LR; + + if (gfp.force_ms) { + gfc.mode_ext = Encoder.MPG_MD_MS_LR; + } else if (gfp.mode == MPEGMode.JOINT_STEREO) { + /* + * ms_ratio = is scaled, for historical reasons, to look like a + * ratio of side_channel / total. 0 = signal is 100% mono .5 = L & R + * uncorrelated + */ + + /** + *
+             * [0] and [1] are the results for the two granules in MPEG-1,
+             * in MPEG-2 it's only a faked averaging of the same value
+             * _prev is the value of the last granule of the previous frame
+             * _next is the value of the first granule of the next frame
+             * 
+ */ + + var sum_pe_MS = 0.; + var sum_pe_LR = 0.; + for (gr = 0; gr < gfc.mode_gr; gr++) { + for (ch = 0; ch < gfc.channels_out; ch++) { + sum_pe_MS += pe_MS[gr][ch]; + sum_pe_LR += pe[gr][ch]; + } + } + + /* based on PE: M/S coding would not use much more bits than L/R */ + if (sum_pe_MS <= 1.00 * sum_pe_LR) { + + var gi0 = gfc.l3_side.tt[0]; + var gi1 = gfc.l3_side.tt[gfc.mode_gr - 1]; + + if (gi0[0].block_type == gi0[1].block_type + && gi1[0].block_type == gi1[1].block_type) { + + gfc.mode_ext = Encoder.MPG_MD_MS_LR; + } + } + } + + /* bit and noise allocation */ + if (gfc.mode_ext == MPG_MD_MS_LR) { + masking = masking_MS; + /* use MS masking */ + pe_use = pe_MS; + } else { + masking = masking_LR; + /* use LR masking */ + pe_use = pe; + } + + /* copy data for MP3 frame analyzer */ + if (gfp.analysis && gfc.pinfo != null) { + for (gr = 0; gr < gfc.mode_gr; gr++) { + for (ch = 0; ch < gfc.channels_out; ch++) { + gfc.pinfo.ms_ratio[gr] = gfc.ms_ratio[gr]; + gfc.pinfo.ms_ener_ratio[gr] = ms_ener_ratio[gr]; + gfc.pinfo.blocktype[gr][ch] = gfc.l3_side.tt[gr][ch].block_type; + gfc.pinfo.pe[gr][ch] = pe_use[gr][ch]; + System.arraycopy(gfc.l3_side.tt[gr][ch].xr, 0, + gfc.pinfo.xr[gr][ch], 0, 576); + /* + * in psymodel, LR and MS data was stored in pinfo. switch + * to MS data: + */ + if (gfc.mode_ext == MPG_MD_MS_LR) { + gfc.pinfo.ers[gr][ch] = gfc.pinfo.ers[gr][ch + 2]; + System.arraycopy(gfc.pinfo.energy[gr][ch + 2], 0, + gfc.pinfo.energy[gr][ch], 0, + gfc.pinfo.energy[gr][ch].length); + } + } + } + } + + /**************************************** + * Stage 4: quantization loop * + ****************************************/ + + if (gfp.VBR == VbrMode.vbr_off || gfp.VBR == VbrMode.vbr_abr) { + + var i; + var f; + + for (i = 0; i < 18; i++) + gfc.nsPsy.pefirbuf[i] = gfc.nsPsy.pefirbuf[i + 1]; + + f = 0.0; + for (gr = 0; gr < gfc.mode_gr; gr++) + for (ch = 0; ch < gfc.channels_out; ch++) + f += pe_use[gr][ch]; + gfc.nsPsy.pefirbuf[18] = f; + + f = gfc.nsPsy.pefirbuf[9]; + for (i = 0; i < 9; i++) + f += (gfc.nsPsy.pefirbuf[i] + gfc.nsPsy.pefirbuf[18 - i]) + * Encoder.fircoef[i]; + + f = (670 * 5 * gfc.mode_gr * gfc.channels_out) / f; + for (gr = 0; gr < gfc.mode_gr; gr++) { + for (ch = 0; ch < gfc.channels_out; ch++) { + pe_use[gr][ch] *= f; + } + } + } + gfc.iteration_loop.iteration_loop(gfp, pe_use, ms_ener_ratio, masking); + + /**************************************** + * Stage 5: bitstream formatting * + ****************************************/ + + /* write the frame to the bitstream */ + bs.format_bitstream(gfp); + + /* copy mp3 bit buffer into array */ + mp3count = bs.copy_buffer(gfc, mp3buf, mp3bufPos, mp3buf_size, 1); + + if (gfp.bWriteVbrTag) + vbr.addVbrFrame(gfp); + + if (gfp.analysis && gfc.pinfo != null) { + for (ch = 0; ch < gfc.channels_out; ch++) { + var j; + for (j = 0; j < FFTOFFSET; j++) + gfc.pinfo.pcmdata[ch][j] = gfc.pinfo.pcmdata[ch][j + + gfp.framesize]; + for (j = FFTOFFSET; j < 1600; j++) { + gfc.pinfo.pcmdata[ch][j] = inbuf[ch][j - FFTOFFSET]; + } + } + qupvt.set_frame_pinfo(gfp, masking); + } + + updateStats(gfc); + + return mp3count; + } +} + + +//package mp3; + +function VBRSeekInfo() { + /** + * What we have seen so far. + */ + this.sum = 0; + /** + * How many frames we have seen in this chunk. + */ + this.seen = 0; + /** + * How many frames we want to collect into one chunk. + */ + this.want = 0; + /** + * Actual position in our bag. + */ + this.pos = 0; + /** + * Size of our bag. + */ + this.size = 0; + /** + * Pointer to our bag. + */ + this.bag = null; + this.nVbrNumFrames = 0; + this.nBytesWritten = 0; + /* VBR tag data */ + this.TotalFrameSize = 0; +} + + + +function IIISideInfo() { + this.tt = [[null, null], [null, null]]; + this.main_data_begin = 0; + this.private_bits = 0; + this.resvDrain_pre = 0; + this.resvDrain_post = 0; + this.scfsi = [new_int(4), new_int(4)]; + + for (var gr = 0; gr < 2; gr++) { + for (var ch = 0; ch < 2; ch++) { + this.tt[gr][ch] = new GrInfo(); + } + } +} + + +function III_psy_xmin() { + this.l = new_float(Encoder.SBMAX_l); + this.s = new_float_n([Encoder.SBMAX_s, 3]); + + var self = this; + this.assign = function (iii_psy_xmin) { + System.arraycopy(iii_psy_xmin.l, 0, self.l, 0, Encoder.SBMAX_l); + for (var i = 0; i < Encoder.SBMAX_s; i++) { + for (var j = 0; j < 3; j++) { + self.s[i][j] = iii_psy_xmin.s[i][j]; + } + } + } +} + + + +//package mp3; + +/** + * Variables used for --nspsytune + * + * @author Ken + * + */ +function NsPsy() { + this.last_en_subshort = new_float_n([4, 9]); + this.lastAttacks = new_int(4); + this.pefirbuf = new_float(19); + this.longfact = new_float(Encoder.SBMAX_l); + this.shortfact = new_float(Encoder.SBMAX_s); + + /** + * short block tuning + */ + this.attackthre = 0.; + this.attackthre_s = 0.; +} + + + + +LameInternalFlags.MFSIZE = (3 * 1152 + Encoder.ENCDELAY - Encoder.MDCTDELAY); +LameInternalFlags.MAX_HEADER_BUF = 256; +LameInternalFlags.MAX_BITS_PER_CHANNEL = 4095; +LameInternalFlags.MAX_BITS_PER_GRANULE = 7680; +LameInternalFlags.BPC = 320; + +function LameInternalFlags() { + var MAX_HEADER_LEN = 40; + + + /******************************************************************** + * internal variables NOT set by calling program, and should not be * + * modified by the calling program * + ********************************************************************/ + + /** + * Some remarks to the Class_ID field: The Class ID is an Identifier for a + * pointer to this struct. It is very unlikely that a pointer to + * lame_global_flags has the same 32 bits in it's structure (large and other + * special properties, for instance prime). + * + * To test that the structure is right and initialized, use: if ( gfc . + * Class_ID == LAME_ID ) ... Other remark: If you set a flag to 0 for uninit + * data and 1 for init data, the right test should be "if (flag == 1)" and + * NOT "if (flag)". Unintended modification of this element will be + * otherwise misinterpreted as an init. + */ + this.Class_ID = 0; + + this.lame_encode_frame_init = 0; + this.iteration_init_init = 0; + this.fill_buffer_resample_init = 0; + + //public float mfbuf[][] = new float[2][MFSIZE]; + this.mfbuf = new_float_n([2, LameInternalFlags.MFSIZE]); + + /** + * granules per frame + */ + this.mode_gr = 0; + /** + * number of channels in the input data stream (PCM or decoded PCM) + */ + this.channels_in = 0; + /** + * number of channels in the output data stream (not used for decoding) + */ + this.channels_out = 0; + /** + * input_samp_rate/output_samp_rate + */ + //public double resample_ratio; + this.resample_ratio = 0.; + + this.mf_samples_to_encode = 0; + this.mf_size = 0; + /** + * min bitrate index + */ + this.VBR_min_bitrate = 0; + /** + * max bitrate index + */ + this.VBR_max_bitrate = 0; + this.bitrate_index = 0; + this.samplerate_index = 0; + this.mode_ext = 0; + + /* lowpass and highpass filter control */ + /** + * normalized frequency bounds of passband + */ + this.lowpass1 = 0.; + this.lowpass2 = 0.; + /** + * normalized frequency bounds of passband + */ + this.highpass1 = 0.; + this.highpass2 = 0.; + + /** + * 0 = none 1 = ISO AAC model 2 = allow scalefac_select=1 + */ + this.noise_shaping = 0; + + /** + * 0 = ISO model: amplify all distorted bands
+ * 1 = amplify within 50% of max (on db scale)
+ * 2 = amplify only most distorted band
+ * 3 = method 1 and refine with method 2
+ */ + this.noise_shaping_amp = 0; + /** + * 0 = no substep
+ * 1 = use substep shaping at last step(VBR only)
+ * (not implemented yet)
+ * 2 = use substep inside loop
+ * 3 = use substep inside loop and last step
+ */ + this.substep_shaping = 0; + + /** + * 1 = gpsycho. 0 = none + */ + this.psymodel = 0; + /** + * 0 = stop at over=0, all scalefacs amplified or
+ * a scalefac has reached max value
+ * 1 = stop when all scalefacs amplified or a scalefac has reached max value
+ * 2 = stop when all scalefacs amplified + */ + this.noise_shaping_stop = 0; + + /** + * 0 = no, 1 = yes + */ + this.subblock_gain = 0; + /** + * 0 = no. 1=outside loop 2=inside loop(slow) + */ + this.use_best_huffman = 0; + + /** + * 0 = stop early after 0 distortion found. 1 = full search + */ + this.full_outer_loop = 0; + + //public IIISideInfo l3_side = new IIISideInfo(); + this.l3_side = new IIISideInfo(); + this.ms_ratio = new_float(2); + + /* used for padding */ + /** + * padding for the current frame? + */ + this.padding = 0; + this.frac_SpF = 0; + this.slot_lag = 0; + + /** + * optional ID3 tags + */ + //public ID3TagSpec tag_spec; + this.tag_spec = null; + this.nMusicCRC = 0; + + /* variables used by Quantize */ + //public int OldValue[] = new int[2]; + this.OldValue = new_int(2); + //public int CurrentStep[] = new int[2]; + this.CurrentStep = new_int(2); + + this.masking_lower = 0.; + //public int bv_scf[] = new int[576]; + this.bv_scf = new_int(576); + //public int pseudohalf[] = new int[L3Side.SFBMAX]; + this.pseudohalf = new_int(L3Side.SFBMAX); + + /** + * will be set in lame_init_params + */ + this.sfb21_extra = false; + + /* BPC = maximum number of filter convolution windows to precompute */ + //public float[][] inbuf_old = new float[2][]; + this.inbuf_old = new Array(2); + //public float[][] blackfilt = new float[2 * BPC + 1][]; + this.blackfilt = new Array(2 * LameInternalFlags.BPC + 1); + //public double itime[] = new double[2]; + this.itime = new_double(2); + this.sideinfo_len = 0; + + /* variables for newmdct.c */ + //public float sb_sample[][][][] = new float[2][2][18][Encoder.SBLIMIT]; + this.sb_sample = new_float_n([2, 2, 18, Encoder.SBLIMIT]); + this.amp_filter = new_float(32); + + /* variables for BitStream */ + + /** + *
+     * mpeg1: buffer=511 bytes  smallest frame: 96-38(sideinfo)=58
+     * max number of frames in reservoir:  8
+     * mpeg2: buffer=255 bytes.  smallest frame: 24-23bytes=1
+     * with VBR, if you are encoding all silence, it is possible to
+     * have 8kbs/24khz frames with 1byte of data each, which means we need
+     * to buffer up to 255 headers!
+     * 
+ */ + /** + * also, max_header_buf has to be a power of two + */ + /** + * max size of header is 38 + */ + + function Header() { + this.write_timing = 0; + this.ptr = 0; + //public byte buf[] = new byte[MAX_HEADER_LEN]; + this.buf = new_byte(MAX_HEADER_LEN); + } + + this.header = new Array(LameInternalFlags.MAX_HEADER_BUF); + + this.h_ptr = 0; + this.w_ptr = 0; + this.ancillary_flag = 0; + + /* variables for Reservoir */ + /** + * in bits + */ + this.ResvSize = 0; + /** + * in bits + */ + this.ResvMax = 0; + + //public ScaleFac scalefac_band = new ScaleFac(); + this.scalefac_band = new ScaleFac(); + + /* daa from PsyModel */ + /* The static variables "r", "phi_sav", "new", "old" and "oldest" have */ + /* to be remembered for the unpredictability measure. For "r" and */ + /* "phi_sav", the first index from the left is the channel select and */ + /* the second index is the "age" of the data. */ + this.minval_l = new_float(Encoder.CBANDS); + this.minval_s = new_float(Encoder.CBANDS); + this.nb_1 = new_float_n([4, Encoder.CBANDS]); + this.nb_2 = new_float_n([4, Encoder.CBANDS]); + this.nb_s1 = new_float_n([4, Encoder.CBANDS]); + this.nb_s2 = new_float_n([4, Encoder.CBANDS]); + this.s3_ss = null; + this.s3_ll = null; + this.decay = 0.; + + //public III_psy_xmin[] thm = new III_psy_xmin[4]; + //public III_psy_xmin[] en = new III_psy_xmin[4]; + this.thm = new Array(4); + this.en = new Array(4); + + /** + * fft and energy calculation + */ + this.tot_ener = new_float(4); + + /* loudness calculation (for adaptive threshold of hearing) */ + /** + * loudness^2 approx. per granule and channel + */ + this.loudness_sq = new_float_n([2, 2]); + /** + * account for granule delay of L3psycho_anal + */ + this.loudness_sq_save = new_float(2); + + /** + * Scale Factor Bands + */ + this.mld_l = new_float(Encoder.SBMAX_l); + this.mld_s = new_float(Encoder.SBMAX_s); + this.bm_l = new_int(Encoder.SBMAX_l); + this.bo_l = new_int(Encoder.SBMAX_l); + this.bm_s = new_int(Encoder.SBMAX_s); + this.bo_s = new_int(Encoder.SBMAX_s); + this.npart_l = 0; + this.npart_s = 0; + + this.s3ind = new_int_n([Encoder.CBANDS, 2]); + this.s3ind_s = new_int_n([Encoder.CBANDS, 2]); + + this.numlines_s = new_int(Encoder.CBANDS); + this.numlines_l = new_int(Encoder.CBANDS); + this.rnumlines_l = new_float(Encoder.CBANDS); + this.mld_cb_l = new_float(Encoder.CBANDS); + this.mld_cb_s = new_float(Encoder.CBANDS); + this.numlines_s_num1 = 0; + this.numlines_l_num1 = 0; + + /* ratios */ + this.pe = new_float(4); + this.ms_ratio_s_old = 0.; + this.ms_ratio_l_old = 0.; + this.ms_ener_ratio_old = 0.; + + /** + * block type + */ + this.blocktype_old = new_int(2); + + /** + * variables used for --nspsytune + */ + this.nsPsy = new NsPsy(); + + /** + * used for Xing VBR header + */ + this.VBR_seek_table = new VBRSeekInfo(); + + /** + * all ATH related stuff + */ + //public ATH ATH; + this.ATH = null; + + this.PSY = null; + + this.nogap_total = 0; + this.nogap_current = 0; + + /* ReplayGain */ + this.decode_on_the_fly = true; + this.findReplayGain = true; + this.findPeakSample = true; + this.PeakSample = 0.; + this.RadioGain = 0; + this.AudiophileGain = 0; + //public ReplayGain rgdata; + this.rgdata = null; + + /** + * gain change required for preventing clipping + */ + this.noclipGainChange = 0; + /** + * user-specified scale factor required for preventing clipping + */ + this.noclipScale = 0.; + + /* simple statistics */ + this.bitrate_stereoMode_Hist = new_int_n([16, 4 + 1]); + /** + * norm/start/short/stop/mixed(short)/sum + */ + this.bitrate_blockType_Hist = new_int_n([16, 4 + 1 + 1]); + + //public PlottingData pinfo; + //public MPGLib.mpstr_tag hip; + this.pinfo = null; + this.hip = null; + + this.in_buffer_nsamples = 0; + //public float[] in_buffer_0; + //public float[] in_buffer_1; + this.in_buffer_0 = null; + this.in_buffer_1 = null; + + //public IIterationLoop iteration_loop; + this.iteration_loop = null; + + for (var i = 0; i < this.en.length; i++) { + this.en[i] = new III_psy_xmin(); + } + for (var i = 0; i < this.thm.length; i++) { + this.thm[i] = new III_psy_xmin(); + } + for (var i = 0; i < this.header.length; i++) { + this.header[i] = new Header(); + } + +} + + + +function FFT() { + + var window = new_float(Encoder.BLKSIZE); + var window_s = new_float(Encoder.BLKSIZE_s / 2); + + var costab = [ + 9.238795325112867e-01, 3.826834323650898e-01, + 9.951847266721969e-01, 9.801714032956060e-02, + 9.996988186962042e-01, 2.454122852291229e-02, + 9.999811752826011e-01, 6.135884649154475e-03 + ]; + + function fht(fz, fzPos, n) { + var tri = 0; + var k4; + var fi; + var gi; + + n <<= 1; + /* to get BLKSIZE, because of 3DNow! ASM routine */ + var fn = fzPos + n; + k4 = 4; + do { + var s1, c1; + var i, k1, k2, k3, kx; + kx = k4 >> 1; + k1 = k4; + k2 = k4 << 1; + k3 = k2 + k1; + k4 = k2 << 1; + fi = fzPos; + gi = fi + kx; + do { + var f0, f1, f2, f3; + f1 = fz[fi + 0] - fz[fi + k1]; + f0 = fz[fi + 0] + fz[fi + k1]; + f3 = fz[fi + k2] - fz[fi + k3]; + f2 = fz[fi + k2] + fz[fi + k3]; + fz[fi + k2] = f0 - f2; + fz[fi + 0] = f0 + f2; + fz[fi + k3] = f1 - f3; + fz[fi + k1] = f1 + f3; + f1 = fz[gi + 0] - fz[gi + k1]; + f0 = fz[gi + 0] + fz[gi + k1]; + f3 = (Util.SQRT2 * fz[gi + k3]); + f2 = (Util.SQRT2 * fz[gi + k2]); + fz[gi + k2] = f0 - f2; + fz[gi + 0] = f0 + f2; + fz[gi + k3] = f1 - f3; + fz[gi + k1] = f1 + f3; + gi += k4; + fi += k4; + } while (fi < fn); + c1 = costab[tri + 0]; + s1 = costab[tri + 1]; + for (i = 1; i < kx; i++) { + var c2, s2; + c2 = 1 - (2 * s1) * s1; + s2 = (2 * s1) * c1; + fi = fzPos + i; + gi = fzPos + k1 - i; + do { + var a, b, g0, f0, f1, g1, f2, g2, f3, g3; + b = s2 * fz[fi + k1] - c2 * fz[gi + k1]; + a = c2 * fz[fi + k1] + s2 * fz[gi + k1]; + f1 = fz[fi + 0] - a; + f0 = fz[fi + 0] + a; + g1 = fz[gi + 0] - b; + g0 = fz[gi + 0] + b; + b = s2 * fz[fi + k3] - c2 * fz[gi + k3]; + a = c2 * fz[fi + k3] + s2 * fz[gi + k3]; + f3 = fz[fi + k2] - a; + f2 = fz[fi + k2] + a; + g3 = fz[gi + k2] - b; + g2 = fz[gi + k2] + b; + b = s1 * f2 - c1 * g3; + a = c1 * f2 + s1 * g3; + fz[fi + k2] = f0 - a; + fz[fi + 0] = f0 + a; + fz[gi + k3] = g1 - b; + fz[gi + k1] = g1 + b; + b = c1 * g2 - s1 * f3; + a = s1 * g2 + c1 * f3; + fz[gi + k2] = g0 - a; + fz[gi + 0] = g0 + a; + fz[fi + k3] = f1 - b; + fz[fi + k1] = f1 + b; + gi += k4; + fi += k4; + } while (fi < fn); + c2 = c1; + c1 = c2 * costab[tri + 0] - s1 * costab[tri + 1]; + s1 = c2 * costab[tri + 1] + s1 * costab[tri + 0]; + } + tri += 2; + } while (k4 < n); + } + + var rv_tbl = [0x00, 0x80, 0x40, + 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, + 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, + 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, + 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, + 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, + 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, + 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, + 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, + 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, + 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, + 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, + 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, + 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, + 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, + 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, + 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, + 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, + 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, + 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, + 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, + 0xde, 0x3e, 0xbe, 0x7e, 0xfe]; + + this.fft_short = function (gfc, x_real, chn, buffer, bufPos) { + for (var b = 0; b < 3; b++) { + var x = Encoder.BLKSIZE_s / 2; + var k = 0xffff & ((576 / 3) * (b + 1)); + var j = Encoder.BLKSIZE_s / 8 - 1; + do { + var f0, f1, f2, f3, w; + var i = rv_tbl[j << 2] & 0xff; + + f0 = window_s[i] * buffer[chn][bufPos + i + k]; + w = window_s[0x7f - i] * buffer[chn][bufPos + i + k + 0x80]; + f1 = f0 - w; + f0 = f0 + w; + f2 = window_s[i + 0x40] * buffer[chn][bufPos + i + k + 0x40]; + w = window_s[0x3f - i] * buffer[chn][bufPos + i + k + 0xc0]; + f3 = f2 - w; + f2 = f2 + w; + + x -= 4; + x_real[b][x + 0] = f0 + f2; + x_real[b][x + 2] = f0 - f2; + x_real[b][x + 1] = f1 + f3; + x_real[b][x + 3] = f1 - f3; + + f0 = window_s[i + 0x01] * buffer[chn][bufPos + i + k + 0x01]; + w = window_s[0x7e - i] * buffer[chn][bufPos + i + k + 0x81]; + f1 = f0 - w; + f0 = f0 + w; + f2 = window_s[i + 0x41] * buffer[chn][bufPos + i + k + 0x41]; + w = window_s[0x3e - i] * buffer[chn][bufPos + i + k + 0xc1]; + f3 = f2 - w; + f2 = f2 + w; + + x_real[b][x + Encoder.BLKSIZE_s / 2 + 0] = f0 + f2; + x_real[b][x + Encoder.BLKSIZE_s / 2 + 2] = f0 - f2; + x_real[b][x + Encoder.BLKSIZE_s / 2 + 1] = f1 + f3; + x_real[b][x + Encoder.BLKSIZE_s / 2 + 3] = f1 - f3; + } while (--j >= 0); + + fht(x_real[b], x, Encoder.BLKSIZE_s / 2); + /* BLKSIZE_s/2 because of 3DNow! ASM routine */ + /* BLKSIZE/2 because of 3DNow! ASM routine */ + } + } + + this.fft_long = function (gfc, y, chn, buffer, bufPos) { + var jj = Encoder.BLKSIZE / 8 - 1; + var x = Encoder.BLKSIZE / 2; + + do { + var f0, f1, f2, f3, w; + var i = rv_tbl[jj] & 0xff; + f0 = window[i] * buffer[chn][bufPos + i]; + w = window[i + 0x200] * buffer[chn][bufPos + i + 0x200]; + f1 = f0 - w; + f0 = f0 + w; + f2 = window[i + 0x100] * buffer[chn][bufPos + i + 0x100]; + w = window[i + 0x300] * buffer[chn][bufPos + i + 0x300]; + f3 = f2 - w; + f2 = f2 + w; + + x -= 4; + y[x + 0] = f0 + f2; + y[x + 2] = f0 - f2; + y[x + 1] = f1 + f3; + y[x + 3] = f1 - f3; + + f0 = window[i + 0x001] * buffer[chn][bufPos + i + 0x001]; + w = window[i + 0x201] * buffer[chn][bufPos + i + 0x201]; + f1 = f0 - w; + f0 = f0 + w; + f2 = window[i + 0x101] * buffer[chn][bufPos + i + 0x101]; + w = window[i + 0x301] * buffer[chn][bufPos + i + 0x301]; + f3 = f2 - w; + f2 = f2 + w; + + y[x + Encoder.BLKSIZE / 2 + 0] = f0 + f2; + y[x + Encoder.BLKSIZE / 2 + 2] = f0 - f2; + y[x + Encoder.BLKSIZE / 2 + 1] = f1 + f3; + y[x + Encoder.BLKSIZE / 2 + 3] = f1 - f3; + } while (--jj >= 0); + + fht(y, x, Encoder.BLKSIZE / 2); + /* BLKSIZE/2 because of 3DNow! ASM routine */ + } + + this.init_fft = function (gfc) { + /* The type of window used here will make no real difference, but */ + /* + * in the interest of merging nspsytune stuff - switch to blackman + * window + */ + for (var i = 0; i < Encoder.BLKSIZE; i++) + /* blackman window */ + window[i] = (0.42 - 0.5 * Math.cos(2 * Math.PI * (i + .5) + / Encoder.BLKSIZE) + 0.08 * Math.cos(4 * Math.PI * (i + .5) + / Encoder.BLKSIZE)); + + for (var i = 0; i < Encoder.BLKSIZE_s / 2; i++) + window_s[i] = (0.5 * (1.0 - Math.cos(2.0 * Math.PI + * (i + 0.5) / Encoder.BLKSIZE_s))); + + } + +} + +/* + * psymodel.c + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 2001-2002 Naoki Shibata + * Copyright (c) 2000-2003 Takehiro Tominaga + * Copyright (c) 2000-2008 Robert Hegemann + * Copyright (c) 2000-2005 Gabriel Bouvigne + * Copyright (c) 2000-2005 Alexander Leidinger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: PsyModel.java,v 1.27 2011/05/24 20:48:06 kenchis Exp $ */ + + +/* + PSYCHO ACOUSTICS + + + This routine computes the psycho acoustics, delayed by one granule. + + Input: buffer of PCM data (1024 samples). + + This window should be centered over the 576 sample granule window. + The routine will compute the psycho acoustics for + this granule, but return the psycho acoustics computed + for the *previous* granule. This is because the block + type of the previous granule can only be determined + after we have computed the psycho acoustics for the following + granule. + + Output: maskings and energies for each scalefactor band. + block type, PE, and some correlation measures. + The PE is used by CBR modes to determine if extra bits + from the bit reservoir should be used. The correlation + measures are used to determine mid/side or regular stereo. + */ +/* + Notation: + + barks: a non-linear frequency scale. Mapping from frequency to + barks is given by freq2bark() + + scalefactor bands: The spectrum (frequencies) are broken into + SBMAX "scalefactor bands". Thes bands + are determined by the MPEG ISO spec. In + the noise shaping/quantization code, we allocate + bits among the partition bands to achieve the + best possible quality + + partition bands: The spectrum is also broken into about + 64 "partition bands". Each partition + band is about .34 barks wide. There are about 2-5 + partition bands for each scalefactor band. + + LAME computes all psycho acoustic information for each partition + band. Then at the end of the computations, this information + is mapped to scalefactor bands. The energy in each scalefactor + band is taken as the sum of the energy in all partition bands + which overlap the scalefactor band. The maskings can be computed + in the same way (and thus represent the average masking in that band) + or by taking the minmum value multiplied by the number of + partition bands used (which represents a minimum masking in that band). + */ +/* + The general outline is as follows: + + 1. compute the energy in each partition band + 2. compute the tonality in each partition band + 3. compute the strength of each partion band "masker" + 4. compute the masking (via the spreading function applied to each masker) + 5. Modifications for mid/side masking. + + Each partition band is considiered a "masker". The strength + of the i'th masker in band j is given by: + + s3(bark(i)-bark(j))*strength(i) + + The strength of the masker is a function of the energy and tonality. + The more tonal, the less masking. LAME uses a simple linear formula + (controlled by NMT and TMN) which says the strength is given by the + energy divided by a linear function of the tonality. + */ +/* + s3() is the "spreading function". It is given by a formula + determined via listening tests. + + The total masking in the j'th partition band is the sum over + all maskings i. It is thus given by the convolution of + the strength with s3(), the "spreading function." + + masking(j) = sum_over_i s3(i-j)*strength(i) = s3 o strength + + where "o" = convolution operator. s3 is given by a formula determined + via listening tests. It is normalized so that s3 o 1 = 1. + + Note: instead of a simple convolution, LAME also has the + option of using "additive masking" + + The most critical part is step 2, computing the tonality of each + partition band. LAME has two tonality estimators. The first + is based on the ISO spec, and measures how predictiable the + signal is over time. The more predictable, the more tonal. + The second measure is based on looking at the spectrum of + a single granule. The more peaky the spectrum, the more + tonal. By most indications, the latter approach is better. + + Finally, in step 5, the maskings for the mid and side + channel are possibly increased. Under certain circumstances, + noise in the mid & side channels is assumed to also + be masked by strong maskers in the L or R channels. + + + Other data computed by the psy-model: + + ms_ratio side-channel / mid-channel masking ratio (for previous granule) + ms_ratio_next side-channel / mid-channel masking ratio for this granule + + percep_entropy[2] L and R values (prev granule) of PE - A measure of how + much pre-echo is in the previous granule + percep_entropy_MS[2] mid and side channel values (prev granule) of percep_entropy + energy[4] L,R,M,S energy in each channel, prev granule + blocktype_d[2] block type to use for previous granule + */ +//package mp3; + +//import java.util.Arrays; + + +function PsyModel() { + + var fft = new FFT(); + + var LOG10 = 2.30258509299404568402; + + var rpelev = 2; + var rpelev2 = 16; + var rpelev_s = 2; + var rpelev2_s = 16; + + /* size of each partition band, in barks: */ + var DELBARK = .34; + + /* tuned for output level (sensitive to energy scale) */ + var VO_SCALE = (1. / (14752 * 14752) / (Encoder.BLKSIZE / 2)); + + var temporalmask_sustain_sec = 0.01; + + var NS_PREECHO_ATT0 = 0.8; + var NS_PREECHO_ATT1 = 0.6; + var NS_PREECHO_ATT2 = 0.3; + + var NS_MSFIX = 3.5; + + var NSATTACKTHRE = 4.4; + var NSATTACKTHRE_S = 25; + + var NSFIRLEN = 21; + + /* size of each partition band, in barks: */ + var LN_TO_LOG10 = 0.2302585093; + + function NON_LINEAR_SCALE_ENERGY(x) { + return x; + } + + /** + *
+     *       L3psycho_anal.  Compute psycho acoustics.
+     *
+     *       Data returned to the calling program must be delayed by one
+     *       granule.
+     *
+     *       This is done in two places.
+     *       If we do not need to know the blocktype, the copying
+     *       can be done here at the top of the program: we copy the data for
+     *       the last granule (computed during the last call) before it is
+     *       overwritten with the new data.  It looks like this:
+     *
+     *       0. static psymodel_data
+     *       1. calling_program_data = psymodel_data
+     *       2. compute psymodel_data
+     *
+     *       For data which needs to know the blocktype, the copying must be
+     *       done at the end of this loop, and the old values must be saved:
+     *
+     *       0. static psymodel_data_old
+     *       1. compute psymodel_data
+     *       2. compute possible block type of this granule
+     *       3. compute final block type of previous granule based on #2.
+     *       4. calling_program_data = psymodel_data_old
+     *       5. psymodel_data_old = psymodel_data
+     *     psycho_loudness_approx
+     *       jd - 2001 mar 12
+     *    in:  energy   - BLKSIZE/2 elements of frequency magnitudes ^ 2
+     *         gfp      - uses out_samplerate, ATHtype (also needed for ATHformula)
+     *    returns: loudness^2 approximation, a positive value roughly tuned for a value
+     *             of 1.0 for signals near clipping.
+     *    notes:   When calibrated, feeding this function binary white noise at sample
+     *             values +32767 or -32768 should return values that approach 3.
+     *             ATHformula is used to approximate an equal loudness curve.
+     *    future:  Data indicates that the shape of the equal loudness curve varies
+     *             with intensity.  This function might be improved by using an equal
+     *             loudness curve shaped for typical playback levels (instead of the
+     *             ATH, that is shaped for the threshold).  A flexible realization might
+     *             simply bend the existing ATH curve to achieve the desired shape.
+     *             However, the potential gain may not be enough to justify an effort.
+     * 
+ */ + function psycho_loudness_approx(energy, gfc) { + var loudness_power = 0.0; + /* apply weights to power in freq. bands */ + for (var i = 0; i < Encoder.BLKSIZE / 2; ++i) + loudness_power += energy[i] * gfc.ATH.eql_w[i]; + loudness_power *= VO_SCALE; + + return loudness_power; + } + + function compute_ffts(gfp, fftenergy, fftenergy_s, wsamp_l, wsamp_lPos, wsamp_s, wsamp_sPos, gr_out, chn, buffer, bufPos) { + var gfc = gfp.internal_flags; + if (chn < 2) { + fft.fft_long(gfc, wsamp_l[wsamp_lPos], chn, buffer, bufPos); + fft.fft_short(gfc, wsamp_s[wsamp_sPos], chn, buffer, bufPos); + } + /* FFT data for mid and side channel is derived from L & R */ + else if (chn == 2) { + for (var j = Encoder.BLKSIZE - 1; j >= 0; --j) { + var l = wsamp_l[wsamp_lPos + 0][j]; + var r = wsamp_l[wsamp_lPos + 1][j]; + wsamp_l[wsamp_lPos + 0][j] = (l + r) * Util.SQRT2 * 0.5; + wsamp_l[wsamp_lPos + 1][j] = (l - r) * Util.SQRT2 * 0.5; + } + for (var b = 2; b >= 0; --b) { + for (var j = Encoder.BLKSIZE_s - 1; j >= 0; --j) { + var l = wsamp_s[wsamp_sPos + 0][b][j]; + var r = wsamp_s[wsamp_sPos + 1][b][j]; + wsamp_s[wsamp_sPos + 0][b][j] = (l + r) * Util.SQRT2 * 0.5; + wsamp_s[wsamp_sPos + 1][b][j] = (l - r) * Util.SQRT2 * 0.5; + } + } + } + + /********************************************************************* + * compute energies + *********************************************************************/ + fftenergy[0] = NON_LINEAR_SCALE_ENERGY(wsamp_l[wsamp_lPos + 0][0]); + fftenergy[0] *= fftenergy[0]; + + for (var j = Encoder.BLKSIZE / 2 - 1; j >= 0; --j) { + var re = (wsamp_l[wsamp_lPos + 0])[Encoder.BLKSIZE / 2 - j]; + var im = (wsamp_l[wsamp_lPos + 0])[Encoder.BLKSIZE / 2 + j]; + fftenergy[Encoder.BLKSIZE / 2 - j] = NON_LINEAR_SCALE_ENERGY((re + * re + im * im) * 0.5); + } + for (var b = 2; b >= 0; --b) { + fftenergy_s[b][0] = (wsamp_s[wsamp_sPos + 0])[b][0]; + fftenergy_s[b][0] *= fftenergy_s[b][0]; + for (var j = Encoder.BLKSIZE_s / 2 - 1; j >= 0; --j) { + var re = (wsamp_s[wsamp_sPos + 0])[b][Encoder.BLKSIZE_s + / 2 - j]; + var im = (wsamp_s[wsamp_sPos + 0])[b][Encoder.BLKSIZE_s + / 2 + j]; + fftenergy_s[b][Encoder.BLKSIZE_s / 2 - j] = NON_LINEAR_SCALE_ENERGY((re + * re + im * im) * 0.5); + } + } + /* total energy */ + { + var totalenergy = 0.0; + for (var j = 11; j < Encoder.HBLKSIZE; j++) + totalenergy += fftenergy[j]; + + gfc.tot_ener[chn] = totalenergy; + } + + if (gfp.analysis) { + for (var j = 0; j < Encoder.HBLKSIZE; j++) { + gfc.pinfo.energy[gr_out][chn][j] = gfc.pinfo.energy_save[chn][j]; + gfc.pinfo.energy_save[chn][j] = fftenergy[j]; + } + gfc.pinfo.pe[gr_out][chn] = gfc.pe[chn]; + } + + /********************************************************************* + * compute loudness approximation (used for ATH auto-level adjustment) + *********************************************************************/ + if (gfp.athaa_loudapprox == 2 && chn < 2) { + // no loudness for mid/side ch + gfc.loudness_sq[gr_out][chn] = gfc.loudness_sq_save[chn]; + gfc.loudness_sq_save[chn] = psycho_loudness_approx(fftenergy, gfc); + } + } + + /* mask_add optimization */ + /* init the limit values used to avoid computing log in mask_add when it is not necessary */ + + /** + *
+     *  For example, with i = 10*log10(m2/m1)/10*16         (= log10(m2/m1)*16)
+     *
+     * abs(i)>8 is equivalent (as i is an integer) to
+     * abs(i)>=9
+     * i>=9 || i<=-9
+     * equivalent to (as i is the biggest integer smaller than log10(m2/m1)*16
+     * or the smallest integer bigger than log10(m2/m1)*16 depending on the sign of log10(m2/m1)*16)
+     * log10(m2/m1)>=9/16 || log10(m2/m1)<=-9/16
+     * exp10 is strictly increasing thus this is equivalent to
+     * m2/m1 >= 10^(9/16) || m2/m1<=10^(-9/16) which are comparisons to constants
+     * 
+ */ + + /** + * as in if(i>8) + */ + var I1LIMIT = 8; + /** + * as in if(i>24) . changed 23 + */ + var I2LIMIT = 23; + /** + * as in if(m<15) + */ + var MLIMIT = 15; + + var ma_max_i1; + var ma_max_i2; + var ma_max_m; + + /** + * This is the masking table:
+ * According to tonality, values are going from 0dB (TMN) to 9.3dB (NMT).
+ * After additive masking computation, 8dB are added, so final values are + * going from 8dB to 17.3dB + * + * pow(10, -0.0..-0.6) + */ + var tab = [1.0, 0.79433, 0.63096, 0.63096, + 0.63096, 0.63096, 0.63096, 0.25119, 0.11749]; + + function init_mask_add_max_values() { + ma_max_i1 = Math.pow(10, (I1LIMIT + 1) / 16.0); + ma_max_i2 = Math.pow(10, (I2LIMIT + 1) / 16.0); + ma_max_m = Math.pow(10, (MLIMIT) / 10.0); + } + + var table1 = [3.3246 * 3.3246, + 3.23837 * 3.23837, 3.15437 * 3.15437, 3.00412 * 3.00412, + 2.86103 * 2.86103, 2.65407 * 2.65407, 2.46209 * 2.46209, + 2.284 * 2.284, 2.11879 * 2.11879, 1.96552 * 1.96552, + 1.82335 * 1.82335, 1.69146 * 1.69146, 1.56911 * 1.56911, + 1.46658 * 1.46658, 1.37074 * 1.37074, 1.31036 * 1.31036, + 1.25264 * 1.25264, 1.20648 * 1.20648, 1.16203 * 1.16203, + 1.12765 * 1.12765, 1.09428 * 1.09428, 1.0659 * 1.0659, + 1.03826 * 1.03826, 1.01895 * 1.01895, 1]; + + var table2 = [1.33352 * 1.33352, + 1.35879 * 1.35879, 1.38454 * 1.38454, 1.39497 * 1.39497, + 1.40548 * 1.40548, 1.3537 * 1.3537, 1.30382 * 1.30382, + 1.22321 * 1.22321, 1.14758 * 1.14758, 1]; + + var table3 = [2.35364 * 2.35364, + 2.29259 * 2.29259, 2.23313 * 2.23313, 2.12675 * 2.12675, + 2.02545 * 2.02545, 1.87894 * 1.87894, 1.74303 * 1.74303, + 1.61695 * 1.61695, 1.49999 * 1.49999, 1.39148 * 1.39148, + 1.29083 * 1.29083, 1.19746 * 1.19746, 1.11084 * 1.11084, + 1.03826 * 1.03826]; + + /** + * addition of simultaneous masking Naoki Shibata 2000/7 + */ + function mask_add(m1, m2, kk, b, gfc, shortblock) { + var ratio; + + if (m2 > m1) { + if (m2 < (m1 * ma_max_i2)) + ratio = m2 / m1; + else + return (m1 + m2); + } else { + if (m1 >= (m2 * ma_max_i2)) + return (m1 + m2); + ratio = m1 / m2; + } + + /* Should always be true, just checking */ + + m1 += m2; + //if (((long)(b + 3) & 0xffffffff) <= 3 + 3) { + if ((b + 3) <= 3 + 3) { + /* approximately, 1 bark = 3 partitions */ + /* 65% of the cases */ + /* originally 'if(i > 8)' */ + if (ratio >= ma_max_i1) { + /* 43% of the total */ + return m1; + } + + /* 22% of the total */ + var i = 0 | (Util.FAST_LOG10_X(ratio, 16.0)); + return m1 * table2[i]; + } + + /** + *
+         * m<15 equ log10((m1+m2)/gfc.ATH.cb[k])<1.5
+         * equ (m1+m2)/gfc.ATH.cb[k]<10^1.5
+         * equ (m1+m2)<10^1.5 * gfc.ATH.cb[k]
+         * 
+ */ + var i = 0 | Util.FAST_LOG10_X(ratio, 16.0); + if (shortblock != 0) { + m2 = gfc.ATH.cb_s[kk] * gfc.ATH.adjust; + } else { + m2 = gfc.ATH.cb_l[kk] * gfc.ATH.adjust; + } + if (m1 < ma_max_m * m2) { + /* 3% of the total */ + /* Originally if (m > 0) { */ + if (m1 > m2) { + var f, r; + + f = 1.0; + if (i <= 13) + f = table3[i]; + + r = Util.FAST_LOG10_X(m1 / m2, 10.0 / 15.0); + return m1 * ((table1[i] - f) * r + f); + } + + if (i > 13) + return m1; + + return m1 * table3[i]; + } + + /* 10% of total */ + return m1 * table1[i]; + } + + var table2_ = [1.33352 * 1.33352, + 1.35879 * 1.35879, 1.38454 * 1.38454, 1.39497 * 1.39497, + 1.40548 * 1.40548, 1.3537 * 1.3537, 1.30382 * 1.30382, + 1.22321 * 1.22321, 1.14758 * 1.14758, 1]; + + /** + * addition of simultaneous masking Naoki Shibata 2000/7 + */ + function vbrpsy_mask_add(m1, m2, b) { + var ratio; + + if (m1 < 0) { + m1 = 0; + } + if (m2 < 0) { + m2 = 0; + } + if (m1 <= 0) { + return m2; + } + if (m2 <= 0) { + return m1; + } + if (m2 > m1) { + ratio = m2 / m1; + } else { + ratio = m1 / m2; + } + if (-2 <= b && b <= 2) { + /* approximately, 1 bark = 3 partitions */ + /* originally 'if(i > 8)' */ + if (ratio >= ma_max_i1) { + return m1 + m2; + } else { + var i = 0 | (Util.FAST_LOG10_X(ratio, 16.0)); + return (m1 + m2) * table2_[i]; + } + } + if (ratio < ma_max_i2) { + return m1 + m2; + } + if (m1 < m2) { + m1 = m2; + } + return m1; + } + + /** + * compute interchannel masking effects + */ + function calc_interchannel_masking(gfp, ratio) { + var gfc = gfp.internal_flags; + if (gfc.channels_out > 1) { + for (var sb = 0; sb < Encoder.SBMAX_l; sb++) { + var l = gfc.thm[0].l[sb]; + var r = gfc.thm[1].l[sb]; + gfc.thm[0].l[sb] += r * ratio; + gfc.thm[1].l[sb] += l * ratio; + } + for (var sb = 0; sb < Encoder.SBMAX_s; sb++) { + for (var sblock = 0; sblock < 3; sblock++) { + var l = gfc.thm[0].s[sb][sblock]; + var r = gfc.thm[1].s[sb][sblock]; + gfc.thm[0].s[sb][sblock] += r * ratio; + gfc.thm[1].s[sb][sblock] += l * ratio; + } + } + } + } + + /** + * compute M/S thresholds from Johnston & Ferreira 1992 ICASSP paper + */ + function msfix1(gfc) { + for (var sb = 0; sb < Encoder.SBMAX_l; sb++) { + /* use this fix if L & R masking differs by 2db or less */ + /* if db = 10*log10(x2/x1) < 2 */ + /* if (x2 < 1.58*x1) { */ + if (gfc.thm[0].l[sb] > 1.58 * gfc.thm[1].l[sb] + || gfc.thm[1].l[sb] > 1.58 * gfc.thm[0].l[sb]) + continue; + var mld = gfc.mld_l[sb] * gfc.en[3].l[sb]; + var rmid = Math.max(gfc.thm[2].l[sb], + Math.min(gfc.thm[3].l[sb], mld)); + + mld = gfc.mld_l[sb] * gfc.en[2].l[sb]; + var rside = Math.max(gfc.thm[3].l[sb], + Math.min(gfc.thm[2].l[sb], mld)); + gfc.thm[2].l[sb] = rmid; + gfc.thm[3].l[sb] = rside; + } + + for (var sb = 0; sb < Encoder.SBMAX_s; sb++) { + for (var sblock = 0; sblock < 3; sblock++) { + if (gfc.thm[0].s[sb][sblock] > 1.58 * gfc.thm[1].s[sb][sblock] + || gfc.thm[1].s[sb][sblock] > 1.58 * gfc.thm[0].s[sb][sblock]) + continue; + var mld = gfc.mld_s[sb] * gfc.en[3].s[sb][sblock]; + var rmid = Math.max(gfc.thm[2].s[sb][sblock], + Math.min(gfc.thm[3].s[sb][sblock], mld)); + + mld = gfc.mld_s[sb] * gfc.en[2].s[sb][sblock]; + var rside = Math.max(gfc.thm[3].s[sb][sblock], + Math.min(gfc.thm[2].s[sb][sblock], mld)); + + gfc.thm[2].s[sb][sblock] = rmid; + gfc.thm[3].s[sb][sblock] = rside; + } + } + } + + /** + * Adjust M/S maskings if user set "msfix" + * + * Naoki Shibata 2000 + */ + function ns_msfix(gfc, msfix, athadjust) { + var msfix2 = msfix; + var athlower = Math.pow(10, athadjust); + + msfix *= 2.0; + msfix2 *= 2.0; + for (var sb = 0; sb < Encoder.SBMAX_l; sb++) { + var thmLR, thmM, thmS, ath; + ath = (gfc.ATH.cb_l[gfc.bm_l[sb]]) * athlower; + thmLR = Math.min(Math.max(gfc.thm[0].l[sb], ath), + Math.max(gfc.thm[1].l[sb], ath)); + thmM = Math.max(gfc.thm[2].l[sb], ath); + thmS = Math.max(gfc.thm[3].l[sb], ath); + if (thmLR * msfix < thmM + thmS) { + var f = thmLR * msfix2 / (thmM + thmS); + thmM *= f; + thmS *= f; + } + gfc.thm[2].l[sb] = Math.min(thmM, gfc.thm[2].l[sb]); + gfc.thm[3].l[sb] = Math.min(thmS, gfc.thm[3].l[sb]); + } + + athlower *= ( Encoder.BLKSIZE_s / Encoder.BLKSIZE); + for (var sb = 0; sb < Encoder.SBMAX_s; sb++) { + for (var sblock = 0; sblock < 3; sblock++) { + var thmLR, thmM, thmS, ath; + ath = (gfc.ATH.cb_s[gfc.bm_s[sb]]) * athlower; + thmLR = Math.min(Math.max(gfc.thm[0].s[sb][sblock], ath), + Math.max(gfc.thm[1].s[sb][sblock], ath)); + thmM = Math.max(gfc.thm[2].s[sb][sblock], ath); + thmS = Math.max(gfc.thm[3].s[sb][sblock], ath); + + if (thmLR * msfix < thmM + thmS) { + var f = thmLR * msfix / (thmM + thmS); + thmM *= f; + thmS *= f; + } + gfc.thm[2].s[sb][sblock] = Math.min(gfc.thm[2].s[sb][sblock], + thmM); + gfc.thm[3].s[sb][sblock] = Math.min(gfc.thm[3].s[sb][sblock], + thmS); + } + } + } + + /** + * short block threshold calculation (part 2) + * + * partition band bo_s[sfb] is at the transition from scalefactor band sfb + * to the next one sfb+1; enn and thmm have to be split between them + */ + function convert_partition2scalefac_s(gfc, eb, thr, chn, sblock) { + var sb, b; + var enn = 0.0; + var thmm = 0.0; + for (sb = b = 0; sb < Encoder.SBMAX_s; ++b, ++sb) { + var bo_s_sb = gfc.bo_s[sb]; + var npart_s = gfc.npart_s; + var b_lim = bo_s_sb < npart_s ? bo_s_sb : npart_s; + while (b < b_lim) { + // iff failed, it may indicate some index error elsewhere + enn += eb[b]; + thmm += thr[b]; + b++; + } + gfc.en[chn].s[sb][sblock] = enn; + gfc.thm[chn].s[sb][sblock] = thmm; + + if (b >= npart_s) { + ++sb; + break; + } + // iff failed, it may indicate some index error elsewhere + { + /* at transition sfb . sfb+1 */ + var w_curr = gfc.PSY.bo_s_weight[sb]; + var w_next = 1.0 - w_curr; + enn = w_curr * eb[b]; + thmm = w_curr * thr[b]; + gfc.en[chn].s[sb][sblock] += enn; + gfc.thm[chn].s[sb][sblock] += thmm; + enn = w_next * eb[b]; + thmm = w_next * thr[b]; + } + } + /* zero initialize the rest */ + for (; sb < Encoder.SBMAX_s; ++sb) { + gfc.en[chn].s[sb][sblock] = 0; + gfc.thm[chn].s[sb][sblock] = 0; + } + } + + /** + * longblock threshold calculation (part 2) + */ + function convert_partition2scalefac_l(gfc, eb, thr, chn) { + var sb, b; + var enn = 0.0; + var thmm = 0.0; + for (sb = b = 0; sb < Encoder.SBMAX_l; ++b, ++sb) { + var bo_l_sb = gfc.bo_l[sb]; + var npart_l = gfc.npart_l; + var b_lim = bo_l_sb < npart_l ? bo_l_sb : npart_l; + while (b < b_lim) { + // iff failed, it may indicate some index error elsewhere + enn += eb[b]; + thmm += thr[b]; + b++; + } + gfc.en[chn].l[sb] = enn; + gfc.thm[chn].l[sb] = thmm; + + if (b >= npart_l) { + ++sb; + break; + } + { + /* at transition sfb . sfb+1 */ + var w_curr = gfc.PSY.bo_l_weight[sb]; + var w_next = 1.0 - w_curr; + enn = w_curr * eb[b]; + thmm = w_curr * thr[b]; + gfc.en[chn].l[sb] += enn; + gfc.thm[chn].l[sb] += thmm; + enn = w_next * eb[b]; + thmm = w_next * thr[b]; + } + } + /* zero initialize the rest */ + for (; sb < Encoder.SBMAX_l; ++sb) { + gfc.en[chn].l[sb] = 0; + gfc.thm[chn].l[sb] = 0; + } + } + + function compute_masking_s(gfp, fftenergy_s, eb, thr, chn, sblock) { + var gfc = gfp.internal_flags; + var j, b; + + for (b = j = 0; b < gfc.npart_s; ++b) { + var ebb = 0, m = 0; + var n = gfc.numlines_s[b]; + for (var i = 0; i < n; ++i, ++j) { + var el = fftenergy_s[sblock][j]; + ebb += el; + if (m < el) + m = el; + } + eb[b] = ebb; + } + for (j = b = 0; b < gfc.npart_s; b++) { + var kk = gfc.s3ind_s[b][0]; + var ecb = gfc.s3_ss[j++] * eb[kk]; + ++kk; + while (kk <= gfc.s3ind_s[b][1]) { + ecb += gfc.s3_ss[j] * eb[kk]; + ++j; + ++kk; + } + + { /* limit calculated threshold by previous granule */ + var x = rpelev_s * gfc.nb_s1[chn][b]; + thr[b] = Math.min(ecb, x); + } + if (gfc.blocktype_old[chn & 1] == Encoder.SHORT_TYPE) { + /* limit calculated threshold by even older granule */ + var x = rpelev2_s * gfc.nb_s2[chn][b]; + var y = thr[b]; + thr[b] = Math.min(x, y); + } + + gfc.nb_s2[chn][b] = gfc.nb_s1[chn][b]; + gfc.nb_s1[chn][b] = ecb; + } + for (; b <= Encoder.CBANDS; ++b) { + eb[b] = 0; + thr[b] = 0; + } + } + + function block_type_set(gfp, uselongblock, blocktype_d, blocktype) { + var gfc = gfp.internal_flags; + + if (gfp.short_blocks == ShortBlock.short_block_coupled + /* force both channels to use the same block type */ + /* this is necessary if the frame is to be encoded in ms_stereo. */ + /* But even without ms_stereo, FhG does this */ + && !(uselongblock[0] != 0 && uselongblock[1] != 0)) + uselongblock[0] = uselongblock[1] = 0; + + /* + * update the blocktype of the previous granule, since it depends on + * what happend in this granule + */ + for (var chn = 0; chn < gfc.channels_out; chn++) { + blocktype[chn] = Encoder.NORM_TYPE; + /* disable short blocks */ + if (gfp.short_blocks == ShortBlock.short_block_dispensed) + uselongblock[chn] = 1; + if (gfp.short_blocks == ShortBlock.short_block_forced) + uselongblock[chn] = 0; + + if (uselongblock[chn] != 0) { + /* no attack : use long blocks */ + if (gfc.blocktype_old[chn] == Encoder.SHORT_TYPE) + blocktype[chn] = Encoder.STOP_TYPE; + } else { + /* attack : use short blocks */ + blocktype[chn] = Encoder.SHORT_TYPE; + if (gfc.blocktype_old[chn] == Encoder.NORM_TYPE) { + gfc.blocktype_old[chn] = Encoder.START_TYPE; + } + if (gfc.blocktype_old[chn] == Encoder.STOP_TYPE) + gfc.blocktype_old[chn] = Encoder.SHORT_TYPE; + } + + blocktype_d[chn] = gfc.blocktype_old[chn]; + // value returned to calling program + gfc.blocktype_old[chn] = blocktype[chn]; + // save for next call to l3psy_anal + } + } + + function NS_INTERP(x, y, r) { + /* was pow((x),(r))*pow((y),1-(r)) */ + if (r >= 1.0) { + /* 99.7% of the time */ + return x; + } + if (r <= 0.0) + return y; + if (y > 0.0) { + /* rest of the time */ + return (Math.pow(x / y, r) * y); + } + /* never happens */ + return 0.0; + } + + /** + * these values are tuned only for 44.1kHz... + */ + var regcoef_s = [11.8, 13.6, 17.2, 32, 46.5, + 51.3, 57.5, 67.1, 71.5, 84.6, 97.6, 130, + /* 255.8 */ + ]; + + function pecalc_s(mr, masking_lower) { + var pe_s = 1236.28 / 4; + for (var sb = 0; sb < Encoder.SBMAX_s - 1; sb++) { + for (var sblock = 0; sblock < 3; sblock++) { + var thm = mr.thm.s[sb][sblock]; + if (thm > 0.0) { + var x = thm * masking_lower; + var en = mr.en.s[sb][sblock]; + if (en > x) { + if (en > x * 1e10) { + pe_s += regcoef_s[sb] * (10.0 * LOG10); + } else { + pe_s += regcoef_s[sb] * Util.FAST_LOG10(en / x); + } + } + } + } + } + + return pe_s; + } + + /** + * these values are tuned only for 44.1kHz... + */ + var regcoef_l = [6.8, 5.8, 5.8, 6.4, 6.5, 9.9, + 12.1, 14.4, 15, 18.9, 21.6, 26.9, 34.2, 40.2, 46.8, 56.5, + 60.7, 73.9, 85.7, 93.4, 126.1, + /* 241.3 */ + ]; + + function pecalc_l(mr, masking_lower) { + var pe_l = 1124.23 / 4; + for (var sb = 0; sb < Encoder.SBMAX_l - 1; sb++) { + var thm = mr.thm.l[sb]; + if (thm > 0.0) { + var x = thm * masking_lower; + var en = mr.en.l[sb]; + if (en > x) { + if (en > x * 1e10) { + pe_l += regcoef_l[sb] * (10.0 * LOG10); + } else { + pe_l += regcoef_l[sb] * Util.FAST_LOG10(en / x); + } + } + } + } + return pe_l; + } + + function calc_energy(gfc, fftenergy, eb, max, avg) { + var b, j; + + for (b = j = 0; b < gfc.npart_l; ++b) { + var ebb = 0, m = 0; + var i; + for (i = 0; i < gfc.numlines_l[b]; ++i, ++j) { + var el = fftenergy[j]; + ebb += el; + if (m < el) + m = el; + } + eb[b] = ebb; + max[b] = m; + avg[b] = ebb * gfc.rnumlines_l[b]; + } + } + + function calc_mask_index_l(gfc, max, avg, mask_idx) { + var last_tab_entry = tab.length - 1; + var b = 0; + var a = avg[b] + avg[b + 1]; + if (a > 0.0) { + var m = max[b]; + if (m < max[b + 1]) + m = max[b + 1]; + a = 20.0 * (m * 2.0 - a) + / (a * (gfc.numlines_l[b] + gfc.numlines_l[b + 1] - 1)); + var k = 0 | a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } else { + mask_idx[b] = 0; + } + + for (b = 1; b < gfc.npart_l - 1; b++) { + a = avg[b - 1] + avg[b] + avg[b + 1]; + if (a > 0.0) { + var m = max[b - 1]; + if (m < max[b]) + m = max[b]; + if (m < max[b + 1]) + m = max[b + 1]; + a = 20.0 + * (m * 3.0 - a) + / (a * (gfc.numlines_l[b - 1] + gfc.numlines_l[b] + + gfc.numlines_l[b + 1] - 1)); + var k = 0 | a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } else { + mask_idx[b] = 0; + } + } + + a = avg[b - 1] + avg[b]; + if (a > 0.0) { + var m = max[b - 1]; + if (m < max[b]) + m = max[b]; + a = 20.0 * (m * 2.0 - a) + / (a * (gfc.numlines_l[b - 1] + gfc.numlines_l[b] - 1)); + var k = 0 | a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } else { + mask_idx[b] = 0; + } + } + + var fircoef = [ + -8.65163e-18 * 2, -0.00851586 * 2, -6.74764e-18 * 2, 0.0209036 * 2, + -3.36639e-17 * 2, -0.0438162 * 2, -1.54175e-17 * 2, 0.0931738 * 2, + -5.52212e-17 * 2, -0.313819 * 2 + ]; + + this.L3psycho_anal_ns = function (gfp, buffer, bufPos, gr_out, masking_ratio, masking_MS_ratio, percep_entropy, percep_MS_entropy, energy, blocktype_d) { + /* + * to get a good cache performance, one has to think about the sequence, + * in which the variables are used. + */ + var gfc = gfp.internal_flags; + + /* fft and energy calculation */ + var wsamp_L = new_float_n([2, Encoder.BLKSIZE]); + var wsamp_S = new_float_n([2, 3, Encoder.BLKSIZE_s]); + + /* convolution */ + var eb_l = new_float(Encoder.CBANDS + 1); + var eb_s = new_float(Encoder.CBANDS + 1); + var thr = new_float(Encoder.CBANDS + 2); + + /* block type */ + var blocktype = new_int(2), uselongblock = new_int(2); + + /* usual variables like loop indices, etc.. */ + var numchn, chn; + var b, i, j, k; + var sb, sblock; + + /* variables used for --nspsytune */ + var ns_hpfsmpl = new_float_n([2, 576]); + var pcfact; + var mask_idx_l = new_int(Encoder.CBANDS + 2), mask_idx_s = new_int(Encoder.CBANDS + 2); + + Arrays.fill(mask_idx_s, 0); + + numchn = gfc.channels_out; + /* chn=2 and 3 = Mid and Side channels */ + if (gfp.mode == MPEGMode.JOINT_STEREO) + numchn = 4; + + if (gfp.VBR == VbrMode.vbr_off) + pcfact = gfc.ResvMax == 0 ? 0 : ( gfc.ResvSize) + / gfc.ResvMax * 0.5; + else if (gfp.VBR == VbrMode.vbr_rh || gfp.VBR == VbrMode.vbr_mtrh + || gfp.VBR == VbrMode.vbr_mt) { + pcfact = 0.6; + } else + pcfact = 1.0; + + /********************************************************************** + * Apply HPF of fs/4 to the input signal. This is used for attack + * detection / handling. + **********************************************************************/ + /* Don't copy the input buffer into a temporary buffer */ + /* unroll the loop 2 times */ + for (chn = 0; chn < gfc.channels_out; chn++) { + /* apply high pass filter of fs/4 */ + var firbuf = buffer[chn]; + var firbufPos = bufPos + 576 - 350 - NSFIRLEN + 192; + for (i = 0; i < 576; i++) { + var sum1, sum2; + sum1 = firbuf[firbufPos + i + 10]; + sum2 = 0.0; + for (j = 0; j < ((NSFIRLEN - 1) / 2) - 1; j += 2) { + sum1 += fircoef[j] + * (firbuf[firbufPos + i + j] + firbuf[firbufPos + i + + NSFIRLEN - j]); + sum2 += fircoef[j + 1] + * (firbuf[firbufPos + i + j + 1] + firbuf[firbufPos + + i + NSFIRLEN - j - 1]); + } + ns_hpfsmpl[chn][i] = sum1 + sum2; + } + masking_ratio[gr_out][chn].en.assign(gfc.en[chn]); + masking_ratio[gr_out][chn].thm.assign(gfc.thm[chn]); + if (numchn > 2) { + /* MS maskings */ + /* percep_MS_entropy [chn-2] = gfc . pe [chn]; */ + masking_MS_ratio[gr_out][chn].en.assign(gfc.en[chn + 2]); + masking_MS_ratio[gr_out][chn].thm.assign(gfc.thm[chn + 2]); + } + } + + for (chn = 0; chn < numchn; chn++) { + var wsamp_l; + var wsamp_s; + var en_subshort = new_float(12); + var en_short = [0, 0, 0, 0]; + var attack_intensity = new_float(12); + var ns_uselongblock = 1; + var attackThreshold; + var max = new_float(Encoder.CBANDS), avg = new_float(Encoder.CBANDS); + var ns_attacks = [0, 0, 0, 0]; + var fftenergy = new_float(Encoder.HBLKSIZE); + var fftenergy_s = new_float_n([3, Encoder.HBLKSIZE_s]); + + /* + * rh 20040301: the following loops do access one off the limits so + * I increase the array dimensions by one and initialize the + * accessed values to zero + */ + + /*************************************************************** + * determine the block type (window type) + ***************************************************************/ + /* calculate energies of each sub-shortblocks */ + for (i = 0; i < 3; i++) { + en_subshort[i] = gfc.nsPsy.last_en_subshort[chn][i + 6]; + attack_intensity[i] = en_subshort[i] + / gfc.nsPsy.last_en_subshort[chn][i + 4]; + en_short[0] += en_subshort[i]; + } + + if (chn == 2) { + for (i = 0; i < 576; i++) { + var l, r; + l = ns_hpfsmpl[0][i]; + r = ns_hpfsmpl[1][i]; + ns_hpfsmpl[0][i] = l + r; + ns_hpfsmpl[1][i] = l - r; + } + } + { + var pf = ns_hpfsmpl[chn & 1]; + var pfPos = 0; + for (i = 0; i < 9; i++) { + var pfe = pfPos + 576 / 9; + var p = 1.; + for (; pfPos < pfe; pfPos++) + if (p < Math.abs(pf[pfPos])) + p = Math.abs(pf[pfPos]); + + gfc.nsPsy.last_en_subshort[chn][i] = en_subshort[i + 3] = p; + en_short[1 + i / 3] += p; + if (p > en_subshort[i + 3 - 2]) { + p = p / en_subshort[i + 3 - 2]; + } else if (en_subshort[i + 3 - 2] > p * 10.0) { + p = en_subshort[i + 3 - 2] / (p * 10.0); + } else + p = 0.0; + attack_intensity[i + 3] = p; + } + } + + if (gfp.analysis) { + var x = attack_intensity[0]; + for (i = 1; i < 12; i++) + if (x < attack_intensity[i]) + x = attack_intensity[i]; + gfc.pinfo.ers[gr_out][chn] = gfc.pinfo.ers_save[chn]; + gfc.pinfo.ers_save[chn] = x; + } + + /* compare energies between sub-shortblocks */ + attackThreshold = (chn == 3) ? gfc.nsPsy.attackthre_s + : gfc.nsPsy.attackthre; + for (i = 0; i < 12; i++) + if (0 == ns_attacks[i / 3] + && attack_intensity[i] > attackThreshold) + ns_attacks[i / 3] = (i % 3) + 1; + + /* + * should have energy change between short blocks, in order to avoid + * periodic signals + */ + for (i = 1; i < 4; i++) { + var ratio; + if (en_short[i - 1] > en_short[i]) { + ratio = en_short[i - 1] / en_short[i]; + } else { + ratio = en_short[i] / en_short[i - 1]; + } + if (ratio < 1.7) { + ns_attacks[i] = 0; + if (i == 1) + ns_attacks[0] = 0; + } + } + + if (ns_attacks[0] != 0 && gfc.nsPsy.lastAttacks[chn] != 0) + ns_attacks[0] = 0; + + if (gfc.nsPsy.lastAttacks[chn] == 3 + || (ns_attacks[0] + ns_attacks[1] + ns_attacks[2] + ns_attacks[3]) != 0) { + ns_uselongblock = 0; + + if (ns_attacks[1] != 0 && ns_attacks[0] != 0) + ns_attacks[1] = 0; + if (ns_attacks[2] != 0 && ns_attacks[1] != 0) + ns_attacks[2] = 0; + if (ns_attacks[3] != 0 && ns_attacks[2] != 0) + ns_attacks[3] = 0; + } + + if (chn < 2) { + uselongblock[chn] = ns_uselongblock; + } else { + if (ns_uselongblock == 0) { + uselongblock[0] = uselongblock[1] = 0; + } + } + + /* + * there is a one granule delay. Copy maskings computed last call + * into masking_ratio to return to calling program. + */ + energy[chn] = gfc.tot_ener[chn]; + + /********************************************************************* + * compute FFTs + *********************************************************************/ + wsamp_s = wsamp_S; + wsamp_l = wsamp_L; + compute_ffts(gfp, fftenergy, fftenergy_s, wsamp_l, (chn & 1), + wsamp_s, (chn & 1), gr_out, chn, buffer, bufPos); + + /********************************************************************* + * Calculate the energy and the tonality of each partition. + *********************************************************************/ + calc_energy(gfc, fftenergy, eb_l, max, avg); + calc_mask_index_l(gfc, max, avg, mask_idx_l); + /* compute masking thresholds for short blocks */ + for (sblock = 0; sblock < 3; sblock++) { + var enn, thmm; + compute_masking_s(gfp, fftenergy_s, eb_s, thr, chn, sblock); + convert_partition2scalefac_s(gfc, eb_s, thr, chn, sblock); + /**** short block pre-echo control ****/ + for (sb = 0; sb < Encoder.SBMAX_s; sb++) { + thmm = gfc.thm[chn].s[sb][sblock]; + + thmm *= NS_PREECHO_ATT0; + if (ns_attacks[sblock] >= 2 || ns_attacks[sblock + 1] == 1) { + var idx = (sblock != 0) ? sblock - 1 : 2; + var p = NS_INTERP(gfc.thm[chn].s[sb][idx], thmm, + NS_PREECHO_ATT1 * pcfact); + thmm = Math.min(thmm, p); + } + + if (ns_attacks[sblock] == 1) { + var idx = (sblock != 0) ? sblock - 1 : 2; + var p = NS_INTERP(gfc.thm[chn].s[sb][idx], thmm, + NS_PREECHO_ATT2 * pcfact); + thmm = Math.min(thmm, p); + } else if ((sblock != 0 && ns_attacks[sblock - 1] == 3) + || (sblock == 0 && gfc.nsPsy.lastAttacks[chn] == 3)) { + var idx = (sblock != 2) ? sblock + 1 : 0; + var p = NS_INTERP(gfc.thm[chn].s[sb][idx], thmm, + NS_PREECHO_ATT2 * pcfact); + thmm = Math.min(thmm, p); + } + + /* pulse like signal detection for fatboy.wav and so on */ + enn = en_subshort[sblock * 3 + 3] + + en_subshort[sblock * 3 + 4] + + en_subshort[sblock * 3 + 5]; + if (en_subshort[sblock * 3 + 5] * 6 < enn) { + thmm *= 0.5; + if (en_subshort[sblock * 3 + 4] * 6 < enn) + thmm *= 0.5; + } + + gfc.thm[chn].s[sb][sblock] = thmm; + } + } + gfc.nsPsy.lastAttacks[chn] = ns_attacks[2]; + + /********************************************************************* + * convolve the partitioned energy and unpredictability with the + * spreading function, s3_l[b][k] + ********************************************************************/ + k = 0; + { + for (b = 0; b < gfc.npart_l; b++) { + /* + * convolve the partitioned energy with the spreading + * function + */ + var kk = gfc.s3ind[b][0]; + var eb2 = eb_l[kk] * tab[mask_idx_l[kk]]; + var ecb = gfc.s3_ll[k++] * eb2; + while (++kk <= gfc.s3ind[b][1]) { + eb2 = eb_l[kk] * tab[mask_idx_l[kk]]; + ecb = mask_add(ecb, gfc.s3_ll[k++] * eb2, kk, kk - b, + gfc, 0); + } + ecb *= 0.158489319246111; + /* pow(10,-0.8) */ + + /**** long block pre-echo control ****/ + /** + *
+                     * dont use long block pre-echo control if previous granule was
+                     * a short block.  This is to avoid the situation:
+                     * frame0:  quiet (very low masking)
+                     * frame1:  surge  (triggers short blocks)
+                     * frame2:  regular frame.  looks like pre-echo when compared to
+                     *          frame0, but all pre-echo was in frame1.
+                     * 
+ */ + /* + * chn=0,1 L and R channels + * + * chn=2,3 S and M channels. + */ + + if (gfc.blocktype_old[chn & 1] == Encoder.SHORT_TYPE) + thr[b] = ecb; + else + thr[b] = NS_INTERP( + Math.min(ecb, Math.min(rpelev + * gfc.nb_1[chn][b], rpelev2 + * gfc.nb_2[chn][b])), ecb, pcfact); + + gfc.nb_2[chn][b] = gfc.nb_1[chn][b]; + gfc.nb_1[chn][b] = ecb; + } + } + for (; b <= Encoder.CBANDS; ++b) { + eb_l[b] = 0; + thr[b] = 0; + } + /* compute masking thresholds for long blocks */ + convert_partition2scalefac_l(gfc, eb_l, thr, chn); + } + /* end loop over chn */ + + if (gfp.mode == MPEGMode.STEREO || gfp.mode == MPEGMode.JOINT_STEREO) { + if (gfp.interChRatio > 0.0) { + calc_interchannel_masking(gfp, gfp.interChRatio); + } + } + + if (gfp.mode == MPEGMode.JOINT_STEREO) { + var msfix; + msfix1(gfc); + msfix = gfp.msfix; + if (Math.abs(msfix) > 0.0) + ns_msfix(gfc, msfix, gfp.ATHlower * gfc.ATH.adjust); + } + + /*************************************************************** + * determine final block type + ***************************************************************/ + block_type_set(gfp, uselongblock, blocktype_d, blocktype); + + /********************************************************************* + * compute the value of PE to return ... no delay and advance + *********************************************************************/ + for (chn = 0; chn < numchn; chn++) { + var ppe; + var ppePos = 0; + var type; + var mr; + + if (chn > 1) { + ppe = percep_MS_entropy; + ppePos = -2; + type = Encoder.NORM_TYPE; + if (blocktype_d[0] == Encoder.SHORT_TYPE + || blocktype_d[1] == Encoder.SHORT_TYPE) + type = Encoder.SHORT_TYPE; + mr = masking_MS_ratio[gr_out][chn - 2]; + } else { + ppe = percep_entropy; + ppePos = 0; + type = blocktype_d[chn]; + mr = masking_ratio[gr_out][chn]; + } + + if (type == Encoder.SHORT_TYPE) + ppe[ppePos + chn] = pecalc_s(mr, gfc.masking_lower); + else + ppe[ppePos + chn] = pecalc_l(mr, gfc.masking_lower); + + if (gfp.analysis) + gfc.pinfo.pe[gr_out][chn] = ppe[ppePos + chn]; + + } + return 0; + } + + function vbrpsy_compute_fft_l(gfp, buffer, bufPos, chn, gr_out, fftenergy, wsamp_l, wsamp_lPos) { + var gfc = gfp.internal_flags; + if (chn < 2) { + fft.fft_long(gfc, wsamp_l[wsamp_lPos], chn, buffer, bufPos); + } else if (chn == 2) { + /* FFT data for mid and side channel is derived from L & R */ + for (var j = Encoder.BLKSIZE - 1; j >= 0; --j) { + var l = wsamp_l[wsamp_lPos + 0][j]; + var r = wsamp_l[wsamp_lPos + 1][j]; + wsamp_l[wsamp_lPos + 0][j] = (l + r) * Util.SQRT2 * 0.5; + wsamp_l[wsamp_lPos + 1][j] = (l - r) * Util.SQRT2 * 0.5; + } + } + + /********************************************************************* + * compute energies + *********************************************************************/ + fftenergy[0] = NON_LINEAR_SCALE_ENERGY(wsamp_l[wsamp_lPos + 0][0]); + fftenergy[0] *= fftenergy[0]; + + for (var j = Encoder.BLKSIZE / 2 - 1; j >= 0; --j) { + var re = wsamp_l[wsamp_lPos + 0][Encoder.BLKSIZE / 2 - j]; + var im = wsamp_l[wsamp_lPos + 0][Encoder.BLKSIZE / 2 + j]; + fftenergy[Encoder.BLKSIZE / 2 - j] = NON_LINEAR_SCALE_ENERGY((re + * re + im * im) * 0.5); + } + /* total energy */ + { + var totalenergy = 0.0; + for (var j = 11; j < Encoder.HBLKSIZE; j++) + totalenergy += fftenergy[j]; + + gfc.tot_ener[chn] = totalenergy; + } + + if (gfp.analysis) { + for (var j = 0; j < Encoder.HBLKSIZE; j++) { + gfc.pinfo.energy[gr_out][chn][j] = gfc.pinfo.energy_save[chn][j]; + gfc.pinfo.energy_save[chn][j] = fftenergy[j]; + } + gfc.pinfo.pe[gr_out][chn] = gfc.pe[chn]; + } + } + + function vbrpsy_compute_fft_s(gfp, buffer, bufPos, chn, sblock, fftenergy_s, wsamp_s, wsamp_sPos) { + var gfc = gfp.internal_flags; + + if (sblock == 0 && chn < 2) { + fft.fft_short(gfc, wsamp_s[wsamp_sPos], chn, buffer, bufPos); + } + if (chn == 2) { + /* FFT data for mid and side channel is derived from L & R */ + for (var j = Encoder.BLKSIZE_s - 1; j >= 0; --j) { + var l = wsamp_s[wsamp_sPos + 0][sblock][j]; + var r = wsamp_s[wsamp_sPos + 1][sblock][j]; + wsamp_s[wsamp_sPos + 0][sblock][j] = (l + r) * Util.SQRT2 * 0.5; + wsamp_s[wsamp_sPos + 1][sblock][j] = (l - r) * Util.SQRT2 * 0.5; + } + } + + /********************************************************************* + * compute energies + *********************************************************************/ + fftenergy_s[sblock][0] = wsamp_s[wsamp_sPos + 0][sblock][0]; + fftenergy_s[sblock][0] *= fftenergy_s[sblock][0]; + for (var j = Encoder.BLKSIZE_s / 2 - 1; j >= 0; --j) { + var re = wsamp_s[wsamp_sPos + 0][sblock][Encoder.BLKSIZE_s / 2 - j]; + var im = wsamp_s[wsamp_sPos + 0][sblock][Encoder.BLKSIZE_s / 2 + j]; + fftenergy_s[sblock][Encoder.BLKSIZE_s / 2 - j] = NON_LINEAR_SCALE_ENERGY((re + * re + im * im) * 0.5); + } + } + + /** + * compute loudness approximation (used for ATH auto-level adjustment) + */ + function vbrpsy_compute_loudness_approximation_l(gfp, gr_out, chn, fftenergy) { + var gfc = gfp.internal_flags; + if (gfp.athaa_loudapprox == 2 && chn < 2) { + // no loudness for mid/side ch + gfc.loudness_sq[gr_out][chn] = gfc.loudness_sq_save[chn]; + gfc.loudness_sq_save[chn] = psycho_loudness_approx(fftenergy, gfc); + } + } + + var fircoef_ = [-8.65163e-18 * 2, + -0.00851586 * 2, -6.74764e-18 * 2, 0.0209036 * 2, + -3.36639e-17 * 2, -0.0438162 * 2, -1.54175e-17 * 2, + 0.0931738 * 2, -5.52212e-17 * 2, -0.313819 * 2]; + + /** + * Apply HPF of fs/4 to the input signal. This is used for attack detection + * / handling. + */ + function vbrpsy_attack_detection(gfp, buffer, bufPos, gr_out, masking_ratio, masking_MS_ratio, energy, sub_short_factor, ns_attacks, uselongblock) { + var ns_hpfsmpl = new_float_n([2, 576]); + var gfc = gfp.internal_flags; + var n_chn_out = gfc.channels_out; + /* chn=2 and 3 = Mid and Side channels */ + var n_chn_psy = (gfp.mode == MPEGMode.JOINT_STEREO) ? 4 : n_chn_out; + /* Don't copy the input buffer into a temporary buffer */ + /* unroll the loop 2 times */ + for (var chn = 0; chn < n_chn_out; chn++) { + /* apply high pass filter of fs/4 */ + firbuf = buffer[chn]; + var firbufPos = bufPos + 576 - 350 - NSFIRLEN + 192; + for (var i = 0; i < 576; i++) { + var sum1, sum2; + sum1 = firbuf[firbufPos + i + 10]; + sum2 = 0.0; + for (var j = 0; j < ((NSFIRLEN - 1) / 2) - 1; j += 2) { + sum1 += fircoef_[j] + * (firbuf[firbufPos + i + j] + firbuf[firbufPos + i + + NSFIRLEN - j]); + sum2 += fircoef_[j + 1] + * (firbuf[firbufPos + i + j + 1] + firbuf[firbufPos + + i + NSFIRLEN - j - 1]); + } + ns_hpfsmpl[chn][i] = sum1 + sum2; + } + masking_ratio[gr_out][chn].en.assign(gfc.en[chn]); + masking_ratio[gr_out][chn].thm.assign(gfc.thm[chn]); + if (n_chn_psy > 2) { + /* MS maskings */ + /* percep_MS_entropy [chn-2] = gfc . pe [chn]; */ + masking_MS_ratio[gr_out][chn].en.assign(gfc.en[chn + 2]); + masking_MS_ratio[gr_out][chn].thm.assign(gfc.thm[chn + 2]); + } + } + for (var chn = 0; chn < n_chn_psy; chn++) { + var attack_intensity = new_float(12); + var en_subshort = new_float(12); + var en_short = [0, 0, 0, 0]; + var pf = ns_hpfsmpl[chn & 1]; + var pfPos = 0; + var attackThreshold = (chn == 3) ? gfc.nsPsy.attackthre_s + : gfc.nsPsy.attackthre; + var ns_uselongblock = 1; + + if (chn == 2) { + for (var i = 0, j = 576; j > 0; ++i, --j) { + var l = ns_hpfsmpl[0][i]; + var r = ns_hpfsmpl[1][i]; + ns_hpfsmpl[0][i] = l + r; + ns_hpfsmpl[1][i] = l - r; + } + } + /*************************************************************** + * determine the block type (window type) + ***************************************************************/ + /* calculate energies of each sub-shortblocks */ + for (var i = 0; i < 3; i++) { + en_subshort[i] = gfc.nsPsy.last_en_subshort[chn][i + 6]; + attack_intensity[i] = en_subshort[i] + / gfc.nsPsy.last_en_subshort[chn][i + 4]; + en_short[0] += en_subshort[i]; + } + + for (var i = 0; i < 9; i++) { + var pfe = pfPos + 576 / 9; + var p = 1.; + for (; pfPos < pfe; pfPos++) + if (p < Math.abs(pf[pfPos])) + p = Math.abs(pf[pfPos]); + + gfc.nsPsy.last_en_subshort[chn][i] = en_subshort[i + 3] = p; + en_short[1 + i / 3] += p; + if (p > en_subshort[i + 3 - 2]) { + p = p / en_subshort[i + 3 - 2]; + } else if (en_subshort[i + 3 - 2] > p * 10.0) { + p = en_subshort[i + 3 - 2] / (p * 10.0); + } else { + p = 0.0; + } + attack_intensity[i + 3] = p; + } + /* pulse like signal detection for fatboy.wav and so on */ + for (var i = 0; i < 3; ++i) { + var enn = en_subshort[i * 3 + 3] + + en_subshort[i * 3 + 4] + en_subshort[i * 3 + 5]; + var factor = 1.; + if (en_subshort[i * 3 + 5] * 6 < enn) { + factor *= 0.5; + if (en_subshort[i * 3 + 4] * 6 < enn) { + factor *= 0.5; + } + } + sub_short_factor[chn][i] = factor; + } + + if (gfp.analysis) { + var x = attack_intensity[0]; + for (var i = 1; i < 12; i++) { + if (x < attack_intensity[i]) { + x = attack_intensity[i]; + } + } + gfc.pinfo.ers[gr_out][chn] = gfc.pinfo.ers_save[chn]; + gfc.pinfo.ers_save[chn] = x; + } + + /* compare energies between sub-shortblocks */ + for (var i = 0; i < 12; i++) { + if (0 == ns_attacks[chn][i / 3] + && attack_intensity[i] > attackThreshold) { + ns_attacks[chn][i / 3] = (i % 3) + 1; + } + } + + /* + * should have energy change between short blocks, in order to avoid + * periodic signals + */ + /* Good samples to show the effect are Trumpet test songs */ + /* + * GB: tuned (1) to avoid too many short blocks for test sample + * TRUMPET + */ + /* + * RH: tuned (2) to let enough short blocks through for test sample + * FSOL and SNAPS + */ + for (var i = 1; i < 4; i++) { + var u = en_short[i - 1]; + var v = en_short[i]; + var m = Math.max(u, v); + if (m < 40000) { /* (2) */ + if (u < 1.7 * v && v < 1.7 * u) { /* (1) */ + if (i == 1 && ns_attacks[chn][0] <= ns_attacks[chn][i]) { + ns_attacks[chn][0] = 0; + } + ns_attacks[chn][i] = 0; + } + } + } + + if (ns_attacks[chn][0] <= gfc.nsPsy.lastAttacks[chn]) { + ns_attacks[chn][0] = 0; + } + + if (gfc.nsPsy.lastAttacks[chn] == 3 + || (ns_attacks[chn][0] + ns_attacks[chn][1] + + ns_attacks[chn][2] + ns_attacks[chn][3]) != 0) { + ns_uselongblock = 0; + + if (ns_attacks[chn][1] != 0 && ns_attacks[chn][0] != 0) { + ns_attacks[chn][1] = 0; + } + if (ns_attacks[chn][2] != 0 && ns_attacks[chn][1] != 0) { + ns_attacks[chn][2] = 0; + } + if (ns_attacks[chn][3] != 0 && ns_attacks[chn][2] != 0) { + ns_attacks[chn][3] = 0; + } + } + if (chn < 2) { + uselongblock[chn] = ns_uselongblock; + } else { + if (ns_uselongblock == 0) { + uselongblock[0] = uselongblock[1] = 0; + } + } + + /* + * there is a one granule delay. Copy maskings computed last call + * into masking_ratio to return to calling program. + */ + energy[chn] = gfc.tot_ener[chn]; + } + } + + function vbrpsy_skip_masking_s(gfc, chn, sblock) { + if (sblock == 0) { + for (var b = 0; b < gfc.npart_s; b++) { + gfc.nb_s2[chn][b] = gfc.nb_s1[chn][b]; + gfc.nb_s1[chn][b] = 0; + } + } + } + + function vbrpsy_skip_masking_l(gfc, chn) { + for (var b = 0; b < gfc.npart_l; b++) { + gfc.nb_2[chn][b] = gfc.nb_1[chn][b]; + gfc.nb_1[chn][b] = 0; + } + } + + function psyvbr_calc_mask_index_s(gfc, max, avg, mask_idx) { + var last_tab_entry = tab.length - 1; + var b = 0; + var a = avg[b] + avg[b + 1]; + if (a > 0.0) { + var m = max[b]; + if (m < max[b + 1]) + m = max[b + 1]; + a = 20.0 * (m * 2.0 - a) + / (a * (gfc.numlines_s[b] + gfc.numlines_s[b + 1] - 1)); + var k = 0 | a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } else { + mask_idx[b] = 0; + } + + for (b = 1; b < gfc.npart_s - 1; b++) { + a = avg[b - 1] + avg[b] + avg[b + 1]; + if (a > 0.0) { + var m = max[b - 1]; + if (m < max[b]) + m = max[b]; + if (m < max[b + 1]) + m = max[b + 1]; + a = 20.0 + * (m * 3.0 - a) + / (a * (gfc.numlines_s[b - 1] + gfc.numlines_s[b] + + gfc.numlines_s[b + 1] - 1)); + var k = 0 | a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } else { + mask_idx[b] = 0; + } + } + + a = avg[b - 1] + avg[b]; + if (a > 0.0) { + var m = max[b - 1]; + if (m < max[b]) + m = max[b]; + a = 20.0 * (m * 2.0 - a) + / (a * (gfc.numlines_s[b - 1] + gfc.numlines_s[b] - 1)); + var k = 0 | a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } else { + mask_idx[b] = 0; + } + } + + function vbrpsy_compute_masking_s(gfp, fftenergy_s, eb, thr, chn, sblock) { + var gfc = gfp.internal_flags; + var max = new float[Encoder.CBANDS], avg = new_float(Encoder.CBANDS); + var i, j, b; + var mask_idx_s = new int[Encoder.CBANDS]; + + for (b = j = 0; b < gfc.npart_s; ++b) { + var ebb = 0, m = 0; + var n = gfc.numlines_s[b]; + for (i = 0; i < n; ++i, ++j) { + var el = fftenergy_s[sblock][j]; + ebb += el; + if (m < el) + m = el; + } + eb[b] = ebb; + max[b] = m; + avg[b] = ebb / n; + } + for (; b < Encoder.CBANDS; ++b) { + max[b] = 0; + avg[b] = 0; + } + psyvbr_calc_mask_index_s(gfc, max, avg, mask_idx_s); + for (j = b = 0; b < gfc.npart_s; b++) { + var kk = gfc.s3ind_s[b][0]; + var last = gfc.s3ind_s[b][1]; + var dd, dd_n; + var x, ecb, avg_mask; + dd = mask_idx_s[kk]; + dd_n = 1; + ecb = gfc.s3_ss[j] * eb[kk] * tab[mask_idx_s[kk]]; + ++j; + ++kk; + while (kk <= last) { + dd += mask_idx_s[kk]; + dd_n += 1; + x = gfc.s3_ss[j] * eb[kk] * tab[mask_idx_s[kk]]; + ecb = vbrpsy_mask_add(ecb, x, kk - b); + ++j; + ++kk; + } + dd = (1 + 2 * dd) / (2 * dd_n); + avg_mask = tab[dd] * 0.5; + ecb *= avg_mask; + thr[b] = ecb; + gfc.nb_s2[chn][b] = gfc.nb_s1[chn][b]; + gfc.nb_s1[chn][b] = ecb; + { + /* + * if THR exceeds EB, the quantization routines will take the + * difference from other bands. in case of strong tonal samples + * (tonaltest.wav) this leads to heavy distortions. that's why + * we limit THR here. + */ + x = max[b]; + x *= gfc.minval_s[b]; + x *= avg_mask; + if (thr[b] > x) { + thr[b] = x; + } + } + if (gfc.masking_lower > 1) { + thr[b] *= gfc.masking_lower; + } + if (thr[b] > eb[b]) { + thr[b] = eb[b]; + } + if (gfc.masking_lower < 1) { + thr[b] *= gfc.masking_lower; + } + + } + for (; b < Encoder.CBANDS; ++b) { + eb[b] = 0; + thr[b] = 0; + } + } + + function vbrpsy_compute_masking_l(gfc, fftenergy, eb_l, thr, chn) { + var max = new_float(Encoder.CBANDS), avg = new_float(Encoder.CBANDS); + var mask_idx_l = new_int(Encoder.CBANDS + 2); + var b; + + /********************************************************************* + * Calculate the energy and the tonality of each partition. + *********************************************************************/ + calc_energy(gfc, fftenergy, eb_l, max, avg); + calc_mask_index_l(gfc, max, avg, mask_idx_l); + + /********************************************************************* + * convolve the partitioned energy and unpredictability with the + * spreading function, s3_l[b][k] + ********************************************************************/ + var k = 0; + for (b = 0; b < gfc.npart_l; b++) { + var x, ecb, avg_mask, t; + /* convolve the partitioned energy with the spreading function */ + var kk = gfc.s3ind[b][0]; + var last = gfc.s3ind[b][1]; + var dd = 0, dd_n = 0; + dd = mask_idx_l[kk]; + dd_n += 1; + ecb = gfc.s3_ll[k] * eb_l[kk] * tab[mask_idx_l[kk]]; + ++k; + ++kk; + while (kk <= last) { + dd += mask_idx_l[kk]; + dd_n += 1; + x = gfc.s3_ll[k] * eb_l[kk] * tab[mask_idx_l[kk]]; + t = vbrpsy_mask_add(ecb, x, kk - b); + ecb = t; + ++k; + ++kk; + } + dd = (1 + 2 * dd) / (2 * dd_n); + avg_mask = tab[dd] * 0.5; + ecb *= avg_mask; + + /**** long block pre-echo control ****/ + /** + *
+             * dont use long block pre-echo control if previous granule was
+             * a short block.  This is to avoid the situation:
+             * frame0:  quiet (very low masking)
+             * frame1:  surge  (triggers short blocks)
+             * frame2:  regular frame.  looks like pre-echo when compared to
+             *          frame0, but all pre-echo was in frame1.
+             * 
+ */ + /* + * chn=0,1 L and R channels chn=2,3 S and M channels. + */ + if (gfc.blocktype_old[chn & 0x01] == Encoder.SHORT_TYPE) { + var ecb_limit = rpelev * gfc.nb_1[chn][b]; + if (ecb_limit > 0) { + thr[b] = Math.min(ecb, ecb_limit); + } else { + /** + *
+                     * Robert 071209:
+                     * Because we don't calculate long block psy when we know a granule
+                     * should be of short blocks, we don't have any clue how the granule
+                     * before would have looked like as a long block. So we have to guess
+                     * a little bit for this END_TYPE block.
+                     * Most of the time we get away with this sloppyness. (fingers crossed :)
+                     * The speed increase is worth it.
+                     * 
+ */ + thr[b] = Math.min(ecb, eb_l[b] * NS_PREECHO_ATT2); + } + } else { + var ecb_limit_2 = rpelev2 * gfc.nb_2[chn][b]; + var ecb_limit_1 = rpelev * gfc.nb_1[chn][b]; + var ecb_limit; + if (ecb_limit_2 <= 0) { + ecb_limit_2 = ecb; + } + if (ecb_limit_1 <= 0) { + ecb_limit_1 = ecb; + } + if (gfc.blocktype_old[chn & 0x01] == Encoder.NORM_TYPE) { + ecb_limit = Math.min(ecb_limit_1, ecb_limit_2); + } else { + ecb_limit = ecb_limit_1; + } + thr[b] = Math.min(ecb, ecb_limit); + } + gfc.nb_2[chn][b] = gfc.nb_1[chn][b]; + gfc.nb_1[chn][b] = ecb; + { + /* + * if THR exceeds EB, the quantization routines will take the + * difference from other bands. in case of strong tonal samples + * (tonaltest.wav) this leads to heavy distortions. that's why + * we limit THR here. + */ + x = max[b]; + x *= gfc.minval_l[b]; + x *= avg_mask; + if (thr[b] > x) { + thr[b] = x; + } + } + if (gfc.masking_lower > 1) { + thr[b] *= gfc.masking_lower; + } + if (thr[b] > eb_l[b]) { + thr[b] = eb_l[b]; + } + if (gfc.masking_lower < 1) { + thr[b] *= gfc.masking_lower; + } + } + for (; b < Encoder.CBANDS; ++b) { + eb_l[b] = 0; + thr[b] = 0; + } + } + + function vbrpsy_compute_block_type(gfp, uselongblock) { + var gfc = gfp.internal_flags; + + if (gfp.short_blocks == ShortBlock.short_block_coupled + /* force both channels to use the same block type */ + /* this is necessary if the frame is to be encoded in ms_stereo. */ + /* But even without ms_stereo, FhG does this */ + && !(uselongblock[0] != 0 && uselongblock[1] != 0)) + uselongblock[0] = uselongblock[1] = 0; + + for (var chn = 0; chn < gfc.channels_out; chn++) { + /* disable short blocks */ + if (gfp.short_blocks == ShortBlock.short_block_dispensed) { + uselongblock[chn] = 1; + } + if (gfp.short_blocks == ShortBlock.short_block_forced) { + uselongblock[chn] = 0; + } + } + } + + function vbrpsy_apply_block_type(gfp, uselongblock, blocktype_d) { + var gfc = gfp.internal_flags; + + /* + * update the blocktype of the previous granule, since it depends on + * what happend in this granule + */ + for (var chn = 0; chn < gfc.channels_out; chn++) { + var blocktype = Encoder.NORM_TYPE; + /* disable short blocks */ + + if (uselongblock[chn] != 0) { + /* no attack : use long blocks */ + if (gfc.blocktype_old[chn] == Encoder.SHORT_TYPE) + blocktype = Encoder.STOP_TYPE; + } else { + /* attack : use short blocks */ + blocktype = Encoder.SHORT_TYPE; + if (gfc.blocktype_old[chn] == Encoder.NORM_TYPE) { + gfc.blocktype_old[chn] = Encoder.START_TYPE; + } + if (gfc.blocktype_old[chn] == Encoder.STOP_TYPE) + gfc.blocktype_old[chn] = Encoder.SHORT_TYPE; + } + + blocktype_d[chn] = gfc.blocktype_old[chn]; + // value returned to calling program + gfc.blocktype_old[chn] = blocktype; + // save for next call to l3psy_anal + } + } + + /** + * compute M/S thresholds from Johnston & Ferreira 1992 ICASSP paper + */ + function vbrpsy_compute_MS_thresholds(eb, thr, cb_mld, ath_cb, athadjust, msfix, n) { + var msfix2 = msfix * 2; + var athlower = msfix > 0 ? Math.pow(10, athadjust) : 1; + var rside, rmid; + for (var b = 0; b < n; ++b) { + var ebM = eb[2][b]; + var ebS = eb[3][b]; + var thmL = thr[0][b]; + var thmR = thr[1][b]; + var thmM = thr[2][b]; + var thmS = thr[3][b]; + + /* use this fix if L & R masking differs by 2db or less */ + if (thmL <= 1.58 * thmR && thmR <= 1.58 * thmL) { + var mld_m = cb_mld[b] * ebS; + var mld_s = cb_mld[b] * ebM; + rmid = Math.max(thmM, Math.min(thmS, mld_m)); + rside = Math.max(thmS, Math.min(thmM, mld_s)); + } else { + rmid = thmM; + rside = thmS; + } + if (msfix > 0) { + /***************************************************************/ + /* Adjust M/S maskings if user set "msfix" */ + /***************************************************************/ + /* Naoki Shibata 2000 */ + var thmLR, thmMS; + var ath = ath_cb[b] * athlower; + thmLR = Math.min(Math.max(thmL, ath), Math.max(thmR, ath)); + thmM = Math.max(rmid, ath); + thmS = Math.max(rside, ath); + thmMS = thmM + thmS; + if (thmMS > 0 && (thmLR * msfix2) < thmMS) { + var f = thmLR * msfix2 / thmMS; + thmM *= f; + thmS *= f; + } + rmid = Math.min(thmM, rmid); + rside = Math.min(thmS, rside); + } + if (rmid > ebM) { + rmid = ebM; + } + if (rside > ebS) { + rside = ebS; + } + thr[2][b] = rmid; + thr[3][b] = rside; + } + } + + this.L3psycho_anal_vbr = function (gfp, buffer, bufPos, gr_out, masking_ratio, masking_MS_ratio, percep_entropy, percep_MS_entropy, energy, blocktype_d) { + var gfc = gfp.internal_flags; + + /* fft and energy calculation */ + var wsamp_l; + var wsamp_s; + var fftenergy = new_float(Encoder.HBLKSIZE); + var fftenergy_s = new_float_n([3, Encoder.HBLKSIZE_s]); + var wsamp_L = new_float_n([2, Encoder.BLKSIZE]); + var wsamp_S = new_float_n([2, 3, Encoder.BLKSIZE_s]); + var eb = new_float_n([4, Encoder.CBANDS]), thr = new_float_n([4, Encoder.CBANDS]); + var sub_short_factor = new_float_n([4, 3]); + var pcfact = 0.6; + + /* block type */ + var ns_attacks = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], + [0, 0, 0, 0]]; + var uselongblock = new_int(2); + + /* usual variables like loop indices, etc.. */ + + /* chn=2 and 3 = Mid and Side channels */ + var n_chn_psy = (gfp.mode == MPEGMode.JOINT_STEREO) ? 4 + : gfc.channels_out; + + vbrpsy_attack_detection(gfp, buffer, bufPos, gr_out, masking_ratio, + masking_MS_ratio, energy, sub_short_factor, ns_attacks, + uselongblock); + + vbrpsy_compute_block_type(gfp, uselongblock); + + /* LONG BLOCK CASE */ + { + for (var chn = 0; chn < n_chn_psy; chn++) { + var ch01 = chn & 0x01; + wsamp_l = wsamp_L; + vbrpsy_compute_fft_l(gfp, buffer, bufPos, chn, gr_out, + fftenergy, wsamp_l, ch01); + + vbrpsy_compute_loudness_approximation_l(gfp, gr_out, chn, + fftenergy); + + if (uselongblock[ch01] != 0) { + vbrpsy_compute_masking_l(gfc, fftenergy, eb[chn], thr[chn], + chn); + } else { + vbrpsy_skip_masking_l(gfc, chn); + } + } + if ((uselongblock[0] + uselongblock[1]) == 2) { + /* M/S channel */ + if (gfp.mode == MPEGMode.JOINT_STEREO) { + vbrpsy_compute_MS_thresholds(eb, thr, gfc.mld_cb_l, + gfc.ATH.cb_l, gfp.ATHlower * gfc.ATH.adjust, + gfp.msfix, gfc.npart_l); + } + } + /* TODO: apply adaptive ATH masking here ?? */ + for (var chn = 0; chn < n_chn_psy; chn++) { + var ch01 = chn & 0x01; + if (uselongblock[ch01] != 0) { + convert_partition2scalefac_l(gfc, eb[chn], thr[chn], chn); + } + } + } + + /* SHORT BLOCKS CASE */ + { + for (var sblock = 0; sblock < 3; sblock++) { + for (var chn = 0; chn < n_chn_psy; ++chn) { + var ch01 = chn & 0x01; + + if (uselongblock[ch01] != 0) { + vbrpsy_skip_masking_s(gfc, chn, sblock); + } else { + /* compute masking thresholds for short blocks */ + wsamp_s = wsamp_S; + vbrpsy_compute_fft_s(gfp, buffer, bufPos, chn, sblock, + fftenergy_s, wsamp_s, ch01); + vbrpsy_compute_masking_s(gfp, fftenergy_s, eb[chn], + thr[chn], chn, sblock); + } + } + if ((uselongblock[0] + uselongblock[1]) == 0) { + /* M/S channel */ + if (gfp.mode == MPEGMode.JOINT_STEREO) { + vbrpsy_compute_MS_thresholds(eb, thr, gfc.mld_cb_s, + gfc.ATH.cb_s, gfp.ATHlower * gfc.ATH.adjust, + gfp.msfix, gfc.npart_s); + } + /* L/R channel */ + } + /* TODO: apply adaptive ATH masking here ?? */ + for (var chn = 0; chn < n_chn_psy; ++chn) { + var ch01 = chn & 0x01; + if (0 == uselongblock[ch01]) { + convert_partition2scalefac_s(gfc, eb[chn], thr[chn], + chn, sblock); + } + } + } + + /**** short block pre-echo control ****/ + for (var chn = 0; chn < n_chn_psy; chn++) { + var ch01 = chn & 0x01; + + if (uselongblock[ch01] != 0) { + continue; + } + for (var sb = 0; sb < Encoder.SBMAX_s; sb++) { + var new_thmm = new_float(3); + for (var sblock = 0; sblock < 3; sblock++) { + var thmm = gfc.thm[chn].s[sb][sblock]; + thmm *= NS_PREECHO_ATT0; + + if (ns_attacks[chn][sblock] >= 2 + || ns_attacks[chn][sblock + 1] == 1) { + var idx = (sblock != 0) ? sblock - 1 : 2; + var p = NS_INTERP(gfc.thm[chn].s[sb][idx], thmm, + NS_PREECHO_ATT1 * pcfact); + thmm = Math.min(thmm, p); + } else if (ns_attacks[chn][sblock] == 1) { + var idx = (sblock != 0) ? sblock - 1 : 2; + var p = NS_INTERP(gfc.thm[chn].s[sb][idx], thmm, + NS_PREECHO_ATT2 * pcfact); + thmm = Math.min(thmm, p); + } else if ((sblock != 0 && ns_attacks[chn][sblock - 1] == 3) + || (sblock == 0 && gfc.nsPsy.lastAttacks[chn] == 3)) { + var idx = (sblock != 2) ? sblock + 1 : 0; + var p = NS_INTERP(gfc.thm[chn].s[sb][idx], thmm, + NS_PREECHO_ATT2 * pcfact); + thmm = Math.min(thmm, p); + } + + /* pulse like signal detection for fatboy.wav and so on */ + thmm *= sub_short_factor[chn][sblock]; + + new_thmm[sblock] = thmm; + } + for (var sblock = 0; sblock < 3; sblock++) { + gfc.thm[chn].s[sb][sblock] = new_thmm[sblock]; + } + } + } + } + for (var chn = 0; chn < n_chn_psy; chn++) { + gfc.nsPsy.lastAttacks[chn] = ns_attacks[chn][2]; + } + + /*************************************************************** + * determine final block type + ***************************************************************/ + vbrpsy_apply_block_type(gfp, uselongblock, blocktype_d); + + /********************************************************************* + * compute the value of PE to return ... no delay and advance + *********************************************************************/ + for (var chn = 0; chn < n_chn_psy; chn++) { + var ppe; + var ppePos; + var type; + var mr; + + if (chn > 1) { + ppe = percep_MS_entropy; + ppePos = -2; + type = Encoder.NORM_TYPE; + if (blocktype_d[0] == Encoder.SHORT_TYPE + || blocktype_d[1] == Encoder.SHORT_TYPE) + type = Encoder.SHORT_TYPE; + mr = masking_MS_ratio[gr_out][chn - 2]; + } else { + ppe = percep_entropy; + ppePos = 0; + type = blocktype_d[chn]; + mr = masking_ratio[gr_out][chn]; + } + + if (type == Encoder.SHORT_TYPE) { + ppe[ppePos + chn] = pecalc_s(mr, gfc.masking_lower); + } else { + ppe[ppePos + chn] = pecalc_l(mr, gfc.masking_lower); + } + + if (gfp.analysis) { + gfc.pinfo.pe[gr_out][chn] = ppe[ppePos + chn]; + } + } + return 0; + } + + function s3_func_x(bark, hf_slope) { + var tempx = bark, tempy; + + if (tempx >= 0) { + tempy = -tempx * 27; + } else { + tempy = tempx * hf_slope; + } + if (tempy <= -72.0) { + return 0; + } + return Math.exp(tempy * LN_TO_LOG10); + } + + function norm_s3_func_x(hf_slope) { + var lim_a = 0, lim_b = 0; + { + var x = 0, l, h; + for (x = 0; s3_func_x(x, hf_slope) > 1e-20; x -= 1) + ; + l = x; + h = 0; + while (Math.abs(h - l) > 1e-12) { + x = (h + l) / 2; + if (s3_func_x(x, hf_slope) > 0) { + h = x; + } else { + l = x; + } + } + lim_a = l; + } + { + var x = 0, l, h; + for (x = 0; s3_func_x(x, hf_slope) > 1e-20; x += 1) + ; + l = 0; + h = x; + while (Math.abs(h - l) > 1e-12) { + x = (h + l) / 2; + if (s3_func_x(x, hf_slope) > 0) { + l = x; + } else { + h = x; + } + } + lim_b = h; + } + { + var sum = 0; + var m = 1000; + var i; + for (i = 0; i <= m; ++i) { + var x = lim_a + i * (lim_b - lim_a) / m; + var y = s3_func_x(x, hf_slope); + sum += y; + } + { + var norm = (m + 1) / (sum * (lim_b - lim_a)); + /* printf( "norm = %lf\n",norm); */ + return norm; + } + } + } + + /** + * The spreading function. Values returned in units of energy + */ + function s3_func(bark) { + var tempx, x, tempy, temp; + tempx = bark; + if (tempx >= 0) + tempx *= 3; + else + tempx *= 1.5; + + if (tempx >= 0.5 && tempx <= 2.5) { + temp = tempx - 0.5; + x = 8.0 * (temp * temp - 2.0 * temp); + } else + x = 0.0; + tempx += 0.474; + tempy = 15.811389 + 7.5 * tempx - 17.5 + * Math.sqrt(1.0 + tempx * tempx); + + if (tempy <= -60.0) + return 0.0; + + tempx = Math.exp((x + tempy) * LN_TO_LOG10); + + /** + *
+         * Normalization.  The spreading function should be normalized so that:
+         * +inf
+         * /
+         * |  s3 [ bark ]  d(bark)   =  1
+         * /
+         * -inf
+         * 
+ */ + tempx /= .6609193; + return tempx; + } + + /** + * see for example "Zwicker: Psychoakustik, 1982; ISBN 3-540-11401-7 + */ + function freq2bark(freq) { + /* input: freq in hz output: barks */ + if (freq < 0) + freq = 0; + freq = freq * 0.001; + return 13.0 * Math.atan(.76 * freq) + 3.5 + * Math.atan(freq * freq / (7.5 * 7.5)); + } + + function init_numline(numlines, bo, bm, bval, bval_width, mld, bo_w, sfreq, blksize, scalepos, deltafreq, sbmax) { + var b_frq = new_float(Encoder.CBANDS + 1); + var sample_freq_frac = sfreq / (sbmax > 15 ? 2 * 576 : 2 * 192); + var partition = new_int(Encoder.HBLKSIZE); + var i; + sfreq /= blksize; + var j = 0; + var ni = 0; + /* compute numlines, the number of spectral lines in each partition band */ + /* each partition band should be about DELBARK wide. */ + for (i = 0; i < Encoder.CBANDS; i++) { + var bark1; + var j2; + bark1 = freq2bark(sfreq * j); + + b_frq[i] = sfreq * j; + + for (j2 = j; freq2bark(sfreq * j2) - bark1 < DELBARK + && j2 <= blksize / 2; j2++) + ; + + numlines[i] = j2 - j; + ni = i + 1; + + while (j < j2) { + partition[j++] = i; + } + if (j > blksize / 2) { + j = blksize / 2; + ++i; + break; + } + } + b_frq[i] = sfreq * j; + + for (var sfb = 0; sfb < sbmax; sfb++) { + var i1, i2, start, end; + var arg; + start = scalepos[sfb]; + end = scalepos[sfb + 1]; + + i1 = 0 | Math.floor(.5 + deltafreq * (start - .5)); + if (i1 < 0) + i1 = 0; + i2 = 0 | Math.floor(.5 + deltafreq * (end - .5)); + + if (i2 > blksize / 2) + i2 = blksize / 2; + + bm[sfb] = (partition[i1] + partition[i2]) / 2; + bo[sfb] = partition[i2]; + var f_tmp = sample_freq_frac * end; + /* + * calculate how much of this band belongs to current scalefactor + * band + */ + bo_w[sfb] = (f_tmp - b_frq[bo[sfb]]) + / (b_frq[bo[sfb] + 1] - b_frq[bo[sfb]]); + if (bo_w[sfb] < 0) { + bo_w[sfb] = 0; + } else { + if (bo_w[sfb] > 1) { + bo_w[sfb] = 1; + } + } + /* setup stereo demasking thresholds */ + /* formula reverse enginerred from plot in paper */ + arg = freq2bark(sfreq * scalepos[sfb] * deltafreq); + arg = ( Math.min(arg, 15.5) / 15.5); + + mld[sfb] = Math.pow(10.0, + 1.25 * (1 - Math.cos(Math.PI * arg)) - 2.5); + } + + /* compute bark values of each critical band */ + j = 0; + for (var k = 0; k < ni; k++) { + var w = numlines[k]; + var bark1, bark2; + + bark1 = freq2bark(sfreq * (j)); + bark2 = freq2bark(sfreq * (j + w - 1)); + bval[k] = .5 * (bark1 + bark2); + + bark1 = freq2bark(sfreq * (j - .5)); + bark2 = freq2bark(sfreq * (j + w - .5)); + bval_width[k] = bark2 - bark1; + j += w; + } + + return ni; + } + + function init_s3_values(s3ind, npart, bval, bval_width, norm, use_old_s3) { + var s3 = new_float_n([Encoder.CBANDS, Encoder.CBANDS]); + /* + * The s3 array is not linear in the bark scale. + * + * bval[x] should be used to get the bark value. + */ + var j; + var numberOfNoneZero = 0; + + /** + *
+         * s[i][j], the value of the spreading function,
+         * centered at band j (masker), for band i (maskee)
+         *
+         * i.e.: sum over j to spread into signal barkval=i
+         * NOTE: i and j are used opposite as in the ISO docs
+         * 
+ */ + if (use_old_s3) { + for (var i = 0; i < npart; i++) { + for (j = 0; j < npart; j++) { + var v = s3_func(bval[i] - bval[j]) * bval_width[j]; + s3[i][j] = v * norm[i]; + } + } + } else { + for (j = 0; j < npart; j++) { + var hf_slope = 15 + Math.min(21 / bval[j], 12); + var s3_x_norm = norm_s3_func_x(hf_slope); + for (var i = 0; i < npart; i++) { + var v = s3_x_norm + * s3_func_x(bval[i] - bval[j], hf_slope) + * bval_width[j]; + s3[i][j] = v * norm[i]; + } + } + } + for (var i = 0; i < npart; i++) { + for (j = 0; j < npart; j++) { + if (s3[i][j] > 0.0) + break; + } + s3ind[i][0] = j; + + for (j = npart - 1; j > 0; j--) { + if (s3[i][j] > 0.0) + break; + } + s3ind[i][1] = j; + numberOfNoneZero += (s3ind[i][1] - s3ind[i][0] + 1); + } + + var p = new_float(numberOfNoneZero); + var k = 0; + for (var i = 0; i < npart; i++) + for (j = s3ind[i][0]; j <= s3ind[i][1]; j++) + p[k++] = s3[i][j]; + + return p; + } + + function stereo_demask(f) { + /* setup stereo demasking thresholds */ + /* formula reverse enginerred from plot in paper */ + var arg = freq2bark(f); + arg = (Math.min(arg, 15.5) / 15.5); + + return Math.pow(10.0, + 1.25 * (1 - Math.cos(Math.PI * arg)) - 2.5); + } + + /** + * NOTE: the bitrate reduction from the inter-channel masking effect is low + * compared to the chance of getting annyoing artefacts. L3psycho_anal_vbr + * does not use this feature. (Robert 071216) + */ + this.psymodel_init = function (gfp) { + var gfc = gfp.internal_flags; + var i; + var useOldS3 = true; + var bvl_a = 13, bvl_b = 24; + var snr_l_a = 0, snr_l_b = 0; + var snr_s_a = -8.25, snr_s_b = -4.5; + var bval = new_float(Encoder.CBANDS); + var bval_width = new_float(Encoder.CBANDS); + var norm = new_float(Encoder.CBANDS); + var sfreq = gfp.out_samplerate; + + switch (gfp.experimentalZ) { + default: + case 0: + useOldS3 = true; + break; + case 1: + useOldS3 = (gfp.VBR == VbrMode.vbr_mtrh || gfp.VBR == VbrMode.vbr_mt) ? false + : true; + break; + case 2: + useOldS3 = false; + break; + case 3: + bvl_a = 8; + snr_l_a = -1.75; + snr_l_b = -0.0125; + snr_s_a = -8.25; + snr_s_b = -2.25; + break; + } + gfc.ms_ener_ratio_old = .25; + gfc.blocktype_old[0] = gfc.blocktype_old[1] = Encoder.NORM_TYPE; + // the vbr header is long blocks + + for (i = 0; i < 4; ++i) { + for (var j = 0; j < Encoder.CBANDS; ++j) { + gfc.nb_1[i][j] = 1e20; + gfc.nb_2[i][j] = 1e20; + gfc.nb_s1[i][j] = gfc.nb_s2[i][j] = 1.0; + } + for (var sb = 0; sb < Encoder.SBMAX_l; sb++) { + gfc.en[i].l[sb] = 1e20; + gfc.thm[i].l[sb] = 1e20; + } + for (var j = 0; j < 3; ++j) { + for (var sb = 0; sb < Encoder.SBMAX_s; sb++) { + gfc.en[i].s[sb][j] = 1e20; + gfc.thm[i].s[sb][j] = 1e20; + } + gfc.nsPsy.lastAttacks[i] = 0; + } + for (var j = 0; j < 9; j++) + gfc.nsPsy.last_en_subshort[i][j] = 10.; + } + + /* init. for loudness approx. -jd 2001 mar 27 */ + gfc.loudness_sq_save[0] = gfc.loudness_sq_save[1] = 0.0; + + /************************************************************************* + * now compute the psychoacoustic model specific constants + ************************************************************************/ + /* compute numlines, bo, bm, bval, bval_width, mld */ + + gfc.npart_l = init_numline(gfc.numlines_l, gfc.bo_l, gfc.bm_l, bval, + bval_width, gfc.mld_l, gfc.PSY.bo_l_weight, sfreq, + Encoder.BLKSIZE, gfc.scalefac_band.l, Encoder.BLKSIZE + / (2.0 * 576), Encoder.SBMAX_l); + /* compute the spreading function */ + for (i = 0; i < gfc.npart_l; i++) { + var snr = snr_l_a; + if (bval[i] >= bvl_a) { + snr = snr_l_b * (bval[i] - bvl_a) / (bvl_b - bvl_a) + snr_l_a + * (bvl_b - bval[i]) / (bvl_b - bvl_a); + } + norm[i] = Math.pow(10.0, snr / 10.0); + if (gfc.numlines_l[i] > 0) { + gfc.rnumlines_l[i] = 1.0 / gfc.numlines_l[i]; + } else { + gfc.rnumlines_l[i] = 0; + } + } + gfc.s3_ll = init_s3_values(gfc.s3ind, gfc.npart_l, bval, bval_width, + norm, useOldS3); + + /* compute long block specific values, ATH and MINVAL */ + var j = 0; + for (i = 0; i < gfc.npart_l; i++) { + var x; + + /* ATH */ + x = Float.MAX_VALUE; + for (var k = 0; k < gfc.numlines_l[i]; k++, j++) { + var freq = sfreq * j / (1000.0 * Encoder.BLKSIZE); + var level; + /* + * ATH below 100 Hz constant, not further climbing + */ + level = this.ATHformula(freq * 1000, gfp) - 20; + // scale to FFT units; returned value is in dB + level = Math.pow(10., 0.1 * level); + // convert from dB . energy + level *= gfc.numlines_l[i]; + if (x > level) + x = level; + } + gfc.ATH.cb_l[i] = x; + + /* + * MINVAL. For low freq, the strength of the masking is limited by + * minval this is an ISO MPEG1 thing, dont know if it is really + * needed + */ + /* + * FIXME: it does work to reduce low-freq problems in S53-Wind-Sax + * and lead-voice samples, but introduces some 3 kbps bit bloat too. + * TODO: Further refinement of the shape of this hack. + */ + x = -20 + bval[i] * 20 / 10; + if (x > 6) { + x = 100; + } + if (x < -15) { + x = -15; + } + x -= 8.; + gfc.minval_l[i] = (Math.pow(10.0, x / 10.) * gfc.numlines_l[i]); + } + + /************************************************************************ + * do the same things for short blocks + ************************************************************************/ + gfc.npart_s = init_numline(gfc.numlines_s, gfc.bo_s, gfc.bm_s, bval, + bval_width, gfc.mld_s, gfc.PSY.bo_s_weight, sfreq, + Encoder.BLKSIZE_s, gfc.scalefac_band.s, Encoder.BLKSIZE_s + / (2.0 * 192), Encoder.SBMAX_s); + + /* SNR formula. short block is normalized by SNR. is it still right ? */ + j = 0; + for (i = 0; i < gfc.npart_s; i++) { + var x; + var snr = snr_s_a; + if (bval[i] >= bvl_a) { + snr = snr_s_b * (bval[i] - bvl_a) / (bvl_b - bvl_a) + snr_s_a + * (bvl_b - bval[i]) / (bvl_b - bvl_a); + } + norm[i] = Math.pow(10.0, snr / 10.0); + + /* ATH */ + x = Float.MAX_VALUE; + for (var k = 0; k < gfc.numlines_s[i]; k++, j++) { + var freq = sfreq * j / (1000.0 * Encoder.BLKSIZE_s); + var level; + /* freq = Min(.1,freq); */ + /* + * ATH below 100 Hz constant, not + * further climbing + */ + level = this.ATHformula(freq * 1000, gfp) - 20; + // scale to FFT units; returned value is in dB + level = Math.pow(10., 0.1 * level); + // convert from dB . energy + level *= gfc.numlines_s[i]; + if (x > level) + x = level; + } + gfc.ATH.cb_s[i] = x; + + /* + * MINVAL. For low freq, the strength of the masking is limited by + * minval this is an ISO MPEG1 thing, dont know if it is really + * needed + */ + x = (-7.0 + bval[i] * 7.0 / 12.0); + if (bval[i] > 12) { + x *= 1 + Math.log(1 + x) * 3.1; + } + if (bval[i] < 12) { + x *= 1 + Math.log(1 - x) * 2.3; + } + if (x < -15) { + x = -15; + } + x -= 8; + gfc.minval_s[i] = Math.pow(10.0, x / 10) + * gfc.numlines_s[i]; + } + + gfc.s3_ss = init_s3_values(gfc.s3ind_s, gfc.npart_s, bval, bval_width, + norm, useOldS3); + + init_mask_add_max_values(); + fft.init_fft(gfc); + + /* setup temporal masking */ + gfc.decay = Math.exp(-1.0 * LOG10 + / (temporalmask_sustain_sec * sfreq / 192.0)); + + { + var msfix; + msfix = NS_MSFIX; + if ((gfp.exp_nspsytune & 2) != 0) + msfix = 1.0; + if (Math.abs(gfp.msfix) > 0.0) + msfix = gfp.msfix; + gfp.msfix = msfix; + + /* + * spread only from npart_l bands. Normally, we use the spreading + * function to convolve from npart_l down to npart_l bands + */ + for (var b = 0; b < gfc.npart_l; b++) + if (gfc.s3ind[b][1] > gfc.npart_l - 1) + gfc.s3ind[b][1] = gfc.npart_l - 1; + } + + /* + * prepare for ATH auto adjustment: we want to decrease the ATH by 12 dB + * per second + */ + var frame_duration = (576. * gfc.mode_gr / sfreq); + gfc.ATH.decay = Math.pow(10., -12. / 10. * frame_duration); + gfc.ATH.adjust = 0.01; + /* minimum, for leading low loudness */ + gfc.ATH.adjustLimit = 1.0; + /* on lead, allow adjust up to maximum */ + + + if (gfp.ATHtype != -1) { + /* compute equal loudness weights (eql_w) */ + var freq; + var freq_inc = gfp.out_samplerate + / (Encoder.BLKSIZE); + var eql_balance = 0.0; + freq = 0.0; + for (i = 0; i < Encoder.BLKSIZE / 2; ++i) { + /* convert ATH dB to relative power (not dB) */ + /* to determine eql_w */ + freq += freq_inc; + gfc.ATH.eql_w[i] = 1. / Math.pow(10, this.ATHformula(freq, gfp) / 10); + eql_balance += gfc.ATH.eql_w[i]; + } + eql_balance = 1.0 / eql_balance; + for (i = Encoder.BLKSIZE / 2; --i >= 0;) { /* scale weights */ + gfc.ATH.eql_w[i] *= eql_balance; + } + } + { + for (var b = j = 0; b < gfc.npart_s; ++b) { + for (i = 0; i < gfc.numlines_s[b]; ++i) { + ++j; + } + } + for (var b = j = 0; b < gfc.npart_l; ++b) { + for (i = 0; i < gfc.numlines_l[b]; ++i) { + ++j; + } + } + } + j = 0; + for (i = 0; i < gfc.npart_l; i++) { + var freq = sfreq * (j + gfc.numlines_l[i] / 2) / (1.0 * Encoder.BLKSIZE); + gfc.mld_cb_l[i] = stereo_demask(freq); + j += gfc.numlines_l[i]; + } + for (; i < Encoder.CBANDS; ++i) { + gfc.mld_cb_l[i] = 1; + } + j = 0; + for (i = 0; i < gfc.npart_s; i++) { + var freq = sfreq * (j + gfc.numlines_s[i] / 2) / (1.0 * Encoder.BLKSIZE_s); + gfc.mld_cb_s[i] = stereo_demask(freq); + j += gfc.numlines_s[i]; + } + for (; i < Encoder.CBANDS; ++i) { + gfc.mld_cb_s[i] = 1; + } + return 0; + } + + /** + * Those ATH formulas are returning their minimum value for input = -1 + */ + function ATHformula_GB(f, value) { + /** + *
+         *  from Painter & Spanias
+         *           modified by Gabriel Bouvigne to better fit the reality
+         *           ath =    3.640 * pow(f,-0.8)
+         *           - 6.800 * exp(-0.6*pow(f-3.4,2.0))
+         *           + 6.000 * exp(-0.15*pow(f-8.7,2.0))
+         *           + 0.6* 0.001 * pow(f,4.0);
+         *
+         *
+         *           In the past LAME was using the Painter &Spanias formula.
+         *           But we had some recurrent problems with HF content.
+         *           We measured real ATH values, and found the older formula
+         *           to be inaccurate in the higher part. So we made this new
+         *           formula and this solved most of HF problematic test cases.
+         *           The tradeoff is that in VBR mode it increases a lot the
+         *           bitrate.
+         * 
+ */ + + /* + * This curve can be adjusted according to the VBR scale: it adjusts + * from something close to Painter & Spanias on V9 up to Bouvigne's + * formula for V0. This way the VBR bitrate is more balanced according + * to the -V value. + */ + + // the following Hack allows to ask for the lowest value + if (f < -.3) + f = 3410; + + // convert to khz + f /= 1000; + f = Math.max(0.1, f); + var ath = 3.640 * Math.pow(f, -0.8) - 6.800 + * Math.exp(-0.6 * Math.pow(f - 3.4, 2.0)) + 6.000 + * Math.exp(-0.15 * Math.pow(f - 8.7, 2.0)) + + (0.6 + 0.04 * value) * 0.001 * Math.pow(f, 4.0); + return ath; + } + + this.ATHformula = function (f, gfp) { + var ath; + switch (gfp.ATHtype) { + case 0: + ath = ATHformula_GB(f, 9); + break; + case 1: + // over sensitive, should probably be removed + ath = ATHformula_GB(f, -1); + break; + case 2: + ath = ATHformula_GB(f, 0); + break; + case 3: + // modification of GB formula by Roel + ath = ATHformula_GB(f, 1) + 6; + break; + case 4: + ath = ATHformula_GB(f, gfp.ATHcurve); + break; + default: + ath = ATHformula_GB(f, 0); + break; + } + return ath; + } + +} + + + +function Lame() { + var self = this; + var LAME_MAXALBUMART = (128 * 1024); + + Lame.V9 = 410; + Lame.V8 = 420; + Lame.V7 = 430; + Lame.V6 = 440; + Lame.V5 = 450; + Lame.V4 = 460; + Lame.V3 = 470; + Lame.V2 = 480; + Lame.V1 = 490; + Lame.V0 = 500; + + /* still there for compatibility */ + + Lame.R3MIX = 1000; + Lame.STANDARD = 1001; + Lame.EXTREME = 1002; + Lame.INSANE = 1003; + Lame.STANDARD_FAST = 1004; + Lame.EXTREME_FAST = 1005; + Lame.MEDIUM = 1006; + Lame.MEDIUM_FAST = 1007; + + /** + * maximum size of mp3buffer needed if you encode at most 1152 samples for + * each call to lame_encode_buffer. see lame_encode_buffer() below + * (LAME_MAXMP3BUFFER is now obsolete) + */ + var LAME_MAXMP3BUFFER = (16384 + LAME_MAXALBUMART); + Lame.LAME_MAXMP3BUFFER = LAME_MAXMP3BUFFER; + + var ga; + var bs; + var p; + var qupvt; + var qu; + var psy = new PsyModel(); + var vbr; + var ver; + var id3; + var mpglib; + this.enc = new Encoder(); + + this.setModules = function (_ga, _bs, _p, _qupvt, _qu, _vbr, _ver, _id3, _mpglib) { + ga = _ga; + bs = _bs; + p = _p; + qupvt = _qupvt; + qu = _qu; + vbr = _vbr; + ver = _ver; + id3 = _id3; + mpglib = _mpglib; + this.enc.setModules(bs, psy, qupvt, vbr); + } + + /** + * PSY Model related stuff + */ + function PSY() { + /** + * The dbQ stuff. + */ + this.mask_adjust = 0.; + /** + * The dbQ stuff. + */ + this.mask_adjust_short = 0.; + /* at transition from one scalefactor band to next */ + /** + * Band weight long scalefactor bands. + */ + this.bo_l_weight = new_float(Encoder.SBMAX_l); + /** + * Band weight short scalefactor bands. + */ + this.bo_s_weight = new_float(Encoder.SBMAX_s); + } + + function LowPassHighPass() { + this.lowerlimit = 0.; + } + + function BandPass(bitrate, lPass) { + this.lowpass = lPass; + } + + var LAME_ID = 0xFFF88E3B; + + function lame_init_old(gfp) { + var gfc; + + gfp.class_id = LAME_ID; + + gfc = gfp.internal_flags = new LameInternalFlags(); + + /* Global flags. set defaults here for non-zero values */ + /* see lame.h for description */ + /* + * set integer values to -1 to mean that LAME will compute the best + * value, UNLESS the calling program as set it (and the value is no + * longer -1) + */ + + gfp.mode = MPEGMode.NOT_SET; + gfp.original = 1; + gfp.in_samplerate = 44100; + gfp.num_channels = 2; + gfp.num_samples = -1; + + gfp.bWriteVbrTag = true; + gfp.quality = -1; + gfp.short_blocks = null; + gfc.subblock_gain = -1; + + gfp.lowpassfreq = 0; + gfp.highpassfreq = 0; + gfp.lowpasswidth = -1; + gfp.highpasswidth = -1; + + gfp.VBR = VbrMode.vbr_off; + gfp.VBR_q = 4; + gfp.ATHcurve = -1; + gfp.VBR_mean_bitrate_kbps = 128; + gfp.VBR_min_bitrate_kbps = 0; + gfp.VBR_max_bitrate_kbps = 0; + gfp.VBR_hard_min = 0; + gfc.VBR_min_bitrate = 1; + /* not 0 ????? */ + gfc.VBR_max_bitrate = 13; + /* not 14 ????? */ + + gfp.quant_comp = -1; + gfp.quant_comp_short = -1; + + gfp.msfix = -1; + + gfc.resample_ratio = 1; + + gfc.OldValue[0] = 180; + gfc.OldValue[1] = 180; + gfc.CurrentStep[0] = 4; + gfc.CurrentStep[1] = 4; + gfc.masking_lower = 1; + gfc.nsPsy.attackthre = -1; + gfc.nsPsy.attackthre_s = -1; + + gfp.scale = -1; + + gfp.athaa_type = -1; + gfp.ATHtype = -1; + /* default = -1 = set in lame_init_params */ + gfp.athaa_loudapprox = -1; + /* 1 = flat loudness approx. (total energy) */ + /* 2 = equal loudness curve */ + gfp.athaa_sensitivity = 0.0; + /* no offset */ + gfp.useTemporal = null; + gfp.interChRatio = -1; + + /* + * The reason for int mf_samples_to_encode = ENCDELAY + POSTDELAY; + * ENCDELAY = internal encoder delay. And then we have to add + * POSTDELAY=288 because of the 50% MDCT overlap. A 576 MDCT granule + * decodes to 1152 samples. To synthesize the 576 samples centered under + * this granule we need the previous granule for the first 288 samples + * (no problem), and the next granule for the next 288 samples (not + * possible if this is last granule). So we need to pad with 288 samples + * to make sure we can encode the 576 samples we are interested in. + */ + gfc.mf_samples_to_encode = Encoder.ENCDELAY + Encoder.POSTDELAY; + gfp.encoder_padding = 0; + gfc.mf_size = Encoder.ENCDELAY - Encoder.MDCTDELAY; + /* + * we pad input with this many 0's + */ + + gfp.findReplayGain = false; + gfp.decode_on_the_fly = false; + + gfc.decode_on_the_fly = false; + gfc.findReplayGain = false; + gfc.findPeakSample = false; + + gfc.RadioGain = 0; + gfc.AudiophileGain = 0; + gfc.noclipGainChange = 0; + gfc.noclipScale = -1.0; + + gfp.preset = 0; + + gfp.write_id3tag_automatic = true; + return 0; + } + + this.lame_init = function () { + var gfp = new LameGlobalFlags(); + + var ret = lame_init_old(gfp); + if (ret != 0) { + return null; + } + + gfp.lame_allocated_gfp = 1; + return gfp; + } + + function filter_coef(x) { + if (x > 1.0) + return 0.0; + if (x <= 0.0) + return 1.0; + + return Math.cos(Math.PI / 2 * x); + } + + this.nearestBitrateFullIndex = function (bitrate) { + /* borrowed from DM abr presets */ + + var full_bitrate_table = [8, 16, 24, 32, 40, 48, 56, 64, 80, + 96, 112, 128, 160, 192, 224, 256, 320]; + + var lower_range = 0, lower_range_kbps = 0, upper_range = 0, upper_range_kbps = 0; + + /* We assume specified bitrate will be 320kbps */ + upper_range_kbps = full_bitrate_table[16]; + upper_range = 16; + lower_range_kbps = full_bitrate_table[16]; + lower_range = 16; + + /* + * Determine which significant bitrates the value specified falls + * between, if loop ends without breaking then we were correct above + * that the value was 320 + */ + for (var b = 0; b < 16; b++) { + if ((Math.max(bitrate, full_bitrate_table[b + 1])) != bitrate) { + upper_range_kbps = full_bitrate_table[b + 1]; + upper_range = b + 1; + lower_range_kbps = full_bitrate_table[b]; + lower_range = (b); + break; + /* We found upper range */ + } + } + + /* Determine which range the value specified is closer to */ + if ((upper_range_kbps - bitrate) > (bitrate - lower_range_kbps)) { + return lower_range; + } + return upper_range; + } + + function optimum_samplefreq(lowpassfreq, input_samplefreq) { + /* + * Rules: + * + * - if possible, sfb21 should NOT be used + */ + var suggested_samplefreq = 44100; + + if (input_samplefreq >= 48000) + suggested_samplefreq = 48000; + else if (input_samplefreq >= 44100) + suggested_samplefreq = 44100; + else if (input_samplefreq >= 32000) + suggested_samplefreq = 32000; + else if (input_samplefreq >= 24000) + suggested_samplefreq = 24000; + else if (input_samplefreq >= 22050) + suggested_samplefreq = 22050; + else if (input_samplefreq >= 16000) + suggested_samplefreq = 16000; + else if (input_samplefreq >= 12000) + suggested_samplefreq = 12000; + else if (input_samplefreq >= 11025) + suggested_samplefreq = 11025; + else if (input_samplefreq >= 8000) + suggested_samplefreq = 8000; + + if (lowpassfreq == -1) + return suggested_samplefreq; + + if (lowpassfreq <= 15960) + suggested_samplefreq = 44100; + if (lowpassfreq <= 15250) + suggested_samplefreq = 32000; + if (lowpassfreq <= 11220) + suggested_samplefreq = 24000; + if (lowpassfreq <= 9970) + suggested_samplefreq = 22050; + if (lowpassfreq <= 7230) + suggested_samplefreq = 16000; + if (lowpassfreq <= 5420) + suggested_samplefreq = 12000; + if (lowpassfreq <= 4510) + suggested_samplefreq = 11025; + if (lowpassfreq <= 3970) + suggested_samplefreq = 8000; + + if (input_samplefreq < suggested_samplefreq) { + /* + * choose a valid MPEG sample frequency above the input sample + * frequency to avoid SFB21/12 bitrate bloat rh 061115 + */ + if (input_samplefreq > 44100) { + return 48000; + } + if (input_samplefreq > 32000) { + return 44100; + } + if (input_samplefreq > 24000) { + return 32000; + } + if (input_samplefreq > 22050) { + return 24000; + } + if (input_samplefreq > 16000) { + return 22050; + } + if (input_samplefreq > 12000) { + return 16000; + } + if (input_samplefreq > 11025) { + return 12000; + } + if (input_samplefreq > 8000) { + return 11025; + } + return 8000; + } + return suggested_samplefreq; + } + + /** + * convert samp freq in Hz to index + */ + function SmpFrqIndex(sample_freq, gpf) { + switch (sample_freq) { + case 44100: + gpf.version = 1; + return 0; + case 48000: + gpf.version = 1; + return 1; + case 32000: + gpf.version = 1; + return 2; + case 22050: + gpf.version = 0; + return 0; + case 24000: + gpf.version = 0; + return 1; + case 16000: + gpf.version = 0; + return 2; + case 11025: + gpf.version = 0; + return 0; + case 12000: + gpf.version = 0; + return 1; + case 8000: + gpf.version = 0; + return 2; + default: + gpf.version = 0; + return -1; + } + } + + /** + * @param bRate + * legal rates from 8 to 320 + */ + function FindNearestBitrate(bRate, version, samplerate) { + /* MPEG-1 or MPEG-2 LSF */ + if (samplerate < 16000) + version = 2; + + var bitrate = Tables.bitrate_table[version][1]; + + for (var i = 2; i <= 14; i++) { + if (Tables.bitrate_table[version][i] > 0) { + if (Math.abs(Tables.bitrate_table[version][i] - bRate) < Math + .abs(bitrate - bRate)) + bitrate = Tables.bitrate_table[version][i]; + } + } + return bitrate; + } + + /** + * @param bRate + * legal rates from 32 to 448 kbps + * @param version + * MPEG-1 or MPEG-2/2.5 LSF + */ + function BitrateIndex(bRate, version, samplerate) { + /* convert bitrate in kbps to index */ + if (samplerate < 16000) + version = 2; + for (var i = 0; i <= 14; i++) { + if (Tables.bitrate_table[version][i] > 0) { + if (Tables.bitrate_table[version][i] == bRate) { + return i; + } + } + } + return -1; + } + + function optimum_bandwidth(lh, bitrate) { + /** + *
+         *  Input:
+         *      bitrate     total bitrate in kbps
+         *
+         *   Output:
+         *      lowerlimit: best lowpass frequency limit for input filter in Hz
+         *      upperlimit: best highpass frequency limit for input filter in Hz
+         * 
+ */ + var freq_map = [new BandPass(8, 2000), + new BandPass(16, 3700), new BandPass(24, 3900), + new BandPass(32, 5500), new BandPass(40, 7000), + new BandPass(48, 7500), new BandPass(56, 10000), + new BandPass(64, 11000), new BandPass(80, 13500), + new BandPass(96, 15100), new BandPass(112, 15600), + new BandPass(128, 17000), new BandPass(160, 17500), + new BandPass(192, 18600), new BandPass(224, 19400), + new BandPass(256, 19700), new BandPass(320, 20500)]; + + var table_index = self.nearestBitrateFullIndex(bitrate); + lh.lowerlimit = freq_map[table_index].lowpass; + } + + function lame_init_params_ppflt(gfp) { + var gfc = gfp.internal_flags; + /***************************************************************/ + /* compute info needed for polyphase filter (filter type==0, default) */ + /***************************************************************/ + + var lowpass_band = 32; + var highpass_band = -1; + + if (gfc.lowpass1 > 0) { + var minband = 999; + for (var band = 0; band <= 31; band++) { + var freq = (band / 31.0); + /* this band and above will be zeroed: */ + if (freq >= gfc.lowpass2) { + lowpass_band = Math.min(lowpass_band, band); + } + if (gfc.lowpass1 < freq && freq < gfc.lowpass2) { + minband = Math.min(minband, band); + } + } + + /* + * compute the *actual* transition band implemented by the polyphase + * filter + */ + if (minband == 999) { + gfc.lowpass1 = (lowpass_band - .75) / 31.0; + } else { + gfc.lowpass1 = (minband - .75) / 31.0; + } + gfc.lowpass2 = lowpass_band / 31.0; + } + + /* + * make sure highpass filter is within 90% of what the effective + * highpass frequency will be + */ + if (gfc.highpass2 > 0) { + if (gfc.highpass2 < .9 * (.75 / 31.0)) { + gfc.highpass1 = 0; + gfc.highpass2 = 0; + System.err.println("Warning: highpass filter disabled. " + + "highpass frequency too small\n"); + } + } + + if (gfc.highpass2 > 0) { + var maxband = -1; + for (var band = 0; band <= 31; band++) { + var freq = band / 31.0; + /* this band and below will be zereod */ + if (freq <= gfc.highpass1) { + highpass_band = Math.max(highpass_band, band); + } + if (gfc.highpass1 < freq && freq < gfc.highpass2) { + maxband = Math.max(maxband, band); + } + } + /* + * compute the *actual* transition band implemented by the polyphase + * filter + */ + gfc.highpass1 = highpass_band / 31.0; + if (maxband == -1) { + gfc.highpass2 = (highpass_band + .75) / 31.0; + } else { + gfc.highpass2 = (maxband + .75) / 31.0; + } + } + + for (var band = 0; band < 32; band++) { + var fc1, fc2; + var freq = band / 31.0; + if (gfc.highpass2 > gfc.highpass1) { + fc1 = filter_coef((gfc.highpass2 - freq) + / (gfc.highpass2 - gfc.highpass1 + 1e-20)); + } else { + fc1 = 1.0; + } + if (gfc.lowpass2 > gfc.lowpass1) { + fc2 = filter_coef((freq - gfc.lowpass1) + / (gfc.lowpass2 - gfc.lowpass1 + 1e-20)); + } else { + fc2 = 1.0; + } + gfc.amp_filter[band] = (fc1 * fc2); + } + } + + function lame_init_qval(gfp) { + var gfc = gfp.internal_flags; + + switch (gfp.quality) { + default: + case 9: /* no psymodel, no noise shaping */ + gfc.psymodel = 0; + gfc.noise_shaping = 0; + gfc.noise_shaping_amp = 0; + gfc.noise_shaping_stop = 0; + gfc.use_best_huffman = 0; + gfc.full_outer_loop = 0; + break; + + case 8: + gfp.quality = 7; + //$FALL-THROUGH$ + case 7: + /* + * use psymodel (for short block and m/s switching), but no noise + * shapping + */ + gfc.psymodel = 1; + gfc.noise_shaping = 0; + gfc.noise_shaping_amp = 0; + gfc.noise_shaping_stop = 0; + gfc.use_best_huffman = 0; + gfc.full_outer_loop = 0; + break; + + case 6: + gfc.psymodel = 1; + if (gfc.noise_shaping == 0) + gfc.noise_shaping = 1; + gfc.noise_shaping_amp = 0; + gfc.noise_shaping_stop = 0; + if (gfc.subblock_gain == -1) + gfc.subblock_gain = 1; + gfc.use_best_huffman = 0; + gfc.full_outer_loop = 0; + break; + + case 5: + gfc.psymodel = 1; + if (gfc.noise_shaping == 0) + gfc.noise_shaping = 1; + gfc.noise_shaping_amp = 0; + gfc.noise_shaping_stop = 0; + if (gfc.subblock_gain == -1) + gfc.subblock_gain = 1; + gfc.use_best_huffman = 0; + gfc.full_outer_loop = 0; + break; + + case 4: + gfc.psymodel = 1; + if (gfc.noise_shaping == 0) + gfc.noise_shaping = 1; + gfc.noise_shaping_amp = 0; + gfc.noise_shaping_stop = 0; + if (gfc.subblock_gain == -1) + gfc.subblock_gain = 1; + gfc.use_best_huffman = 1; + gfc.full_outer_loop = 0; + break; + + case 3: + gfc.psymodel = 1; + if (gfc.noise_shaping == 0) + gfc.noise_shaping = 1; + gfc.noise_shaping_amp = 1; + gfc.noise_shaping_stop = 1; + if (gfc.subblock_gain == -1) + gfc.subblock_gain = 1; + gfc.use_best_huffman = 1; + gfc.full_outer_loop = 0; + break; + + case 2: + gfc.psymodel = 1; + if (gfc.noise_shaping == 0) + gfc.noise_shaping = 1; + if (gfc.substep_shaping == 0) + gfc.substep_shaping = 2; + gfc.noise_shaping_amp = 1; + gfc.noise_shaping_stop = 1; + if (gfc.subblock_gain == -1) + gfc.subblock_gain = 1; + gfc.use_best_huffman = 1; + /* inner loop */ + gfc.full_outer_loop = 0; + break; + + case 1: + gfc.psymodel = 1; + if (gfc.noise_shaping == 0) + gfc.noise_shaping = 1; + if (gfc.substep_shaping == 0) + gfc.substep_shaping = 2; + gfc.noise_shaping_amp = 2; + gfc.noise_shaping_stop = 1; + if (gfc.subblock_gain == -1) + gfc.subblock_gain = 1; + gfc.use_best_huffman = 1; + gfc.full_outer_loop = 0; + break; + + case 0: + gfc.psymodel = 1; + if (gfc.noise_shaping == 0) + gfc.noise_shaping = 1; + if (gfc.substep_shaping == 0) + gfc.substep_shaping = 2; + gfc.noise_shaping_amp = 2; + gfc.noise_shaping_stop = 1; + if (gfc.subblock_gain == -1) + gfc.subblock_gain = 1; + gfc.use_best_huffman = 1; + /* + * type 2 disabled because of it slowness, in favor of full outer + * loop search + */ + gfc.full_outer_loop = 0; + /* + * full outer loop search disabled because of audible distortions it + * may generate rh 060629 + */ + break; + } + + } + + function lame_init_bitstream(gfp) { + var gfc = gfp.internal_flags; + gfp.frameNum = 0; + + if (gfp.write_id3tag_automatic) { + id3.id3tag_write_v2(gfp); + } + /* initialize histogram data optionally used by frontend */ + + gfc.bitrate_stereoMode_Hist = new_int_n([16, 4 + 1]); + gfc.bitrate_blockType_Hist = new_int_n([16, 4 + 1 + 1]); + + gfc.PeakSample = 0.0; + + /* Write initial VBR Header to bitstream and init VBR data */ + if (gfp.bWriteVbrTag) + vbr.InitVbrTag(gfp); + } + + /******************************************************************** + * initialize internal params based on data in gf (globalflags struct filled + * in by calling program) + * + * OUTLINE: + * + * We first have some complex code to determine bitrate, output samplerate + * and mode. It is complicated by the fact that we allow the user to set + * some or all of these parameters, and need to determine best possible + * values for the rest of them: + * + * 1. set some CPU related flags 2. check if we are mono.mono, stereo.mono + * or stereo.stereo 3. compute bitrate and output samplerate: user may have + * set compression ratio user may have set a bitrate user may have set a + * output samplerate 4. set some options which depend on output samplerate + * 5. compute the actual compression ratio 6. set mode based on compression + * ratio + * + * The remaining code is much simpler - it just sets options based on the + * mode & compression ratio: + * + * set allow_diff_short based on mode select lowpass filter based on + * compression ratio & mode set the bitrate index, and min/max bitrates for + * VBR modes disable VBR tag if it is not appropriate initialize the + * bitstream initialize scalefac_band data set sideinfo_len (based on + * channels, CRC, out_samplerate) write an id3v2 tag into the bitstream + * write VBR tag into the bitstream set mpeg1/2 flag estimate the number of + * frames (based on a lot of data) + * + * now we set more flags: nspsytune: see code VBR modes see code CBR/ABR see + * code + * + * Finally, we set the algorithm flags based on the gfp.quality value + * lame_init_qval(gfp); + * + ********************************************************************/ + this.lame_init_params = function (gfp) { + var gfc = gfp.internal_flags; + + gfc.Class_ID = 0; + if (gfc.ATH == null) + gfc.ATH = new ATH(); + if (gfc.PSY == null) + gfc.PSY = new PSY(); + if (gfc.rgdata == null) + gfc.rgdata = new ReplayGain(); + + gfc.channels_in = gfp.num_channels; + if (gfc.channels_in == 1) + gfp.mode = MPEGMode.MONO; + gfc.channels_out = (gfp.mode == MPEGMode.MONO) ? 1 : 2; + gfc.mode_ext = Encoder.MPG_MD_MS_LR; + if (gfp.mode == MPEGMode.MONO) + gfp.force_ms = false; + /* + * don't allow forced mid/side stereo for mono output + */ + + if (gfp.VBR == VbrMode.vbr_off && gfp.VBR_mean_bitrate_kbps != 128 + && gfp.brate == 0) + gfp.brate = gfp.VBR_mean_bitrate_kbps; + + if (gfp.VBR == VbrMode.vbr_off || gfp.VBR == VbrMode.vbr_mtrh + || gfp.VBR == VbrMode.vbr_mt) { + /* these modes can handle free format condition */ + } else { + gfp.free_format = false; + /* mode can't be mixed with free format */ + } + + if (gfp.VBR == VbrMode.vbr_off && gfp.brate == 0) { + /* no bitrate or compression ratio specified, use 11.025 */ + if (BitStream.EQ(gfp.compression_ratio, 0)) + gfp.compression_ratio = 11.025; + /* + * rate to compress a CD down to exactly 128000 bps + */ + } + + /* find bitrate if user specify a compression ratio */ + if (gfp.VBR == VbrMode.vbr_off && gfp.compression_ratio > 0) { + + if (gfp.out_samplerate == 0) + gfp.out_samplerate = map2MP3Frequency((int)(0.97 * gfp.in_samplerate)); + /* + * round up with a margin of 3 % + */ + + /* + * choose a bitrate for the output samplerate which achieves + * specified compression ratio + */ + gfp.brate = 0 | (gfp.out_samplerate * 16 * gfc.channels_out / (1.e3 * gfp.compression_ratio)); + + /* we need the version for the bitrate table look up */ + gfc.samplerate_index = SmpFrqIndex(gfp.out_samplerate, gfp); + + if (!gfp.free_format) /* + * for non Free Format find the nearest allowed + * bitrate + */ + gfp.brate = FindNearestBitrate(gfp.brate, gfp.version, + gfp.out_samplerate); + } + + if (gfp.out_samplerate != 0) { + if (gfp.out_samplerate < 16000) { + gfp.VBR_mean_bitrate_kbps = Math.max(gfp.VBR_mean_bitrate_kbps, + 8); + gfp.VBR_mean_bitrate_kbps = Math.min(gfp.VBR_mean_bitrate_kbps, + 64); + } else if (gfp.out_samplerate < 32000) { + gfp.VBR_mean_bitrate_kbps = Math.max(gfp.VBR_mean_bitrate_kbps, + 8); + gfp.VBR_mean_bitrate_kbps = Math.min(gfp.VBR_mean_bitrate_kbps, + 160); + } else { + gfp.VBR_mean_bitrate_kbps = Math.max(gfp.VBR_mean_bitrate_kbps, + 32); + gfp.VBR_mean_bitrate_kbps = Math.min(gfp.VBR_mean_bitrate_kbps, + 320); + } + } + + /****************************************************************/ + /* if a filter has not been enabled, see if we should add one: */ + /****************************************************************/ + if (gfp.lowpassfreq == 0) { + var lowpass = 16000.; + + switch (gfp.VBR) { + case VbrMode.vbr_off: + { + var lh = new LowPassHighPass(); + optimum_bandwidth(lh, gfp.brate); + lowpass = lh.lowerlimit; + break; + } + case VbrMode.vbr_abr: + { + var lh = new LowPassHighPass(); + optimum_bandwidth(lh, gfp.VBR_mean_bitrate_kbps); + lowpass = lh.lowerlimit; + break; + } + case VbrMode.vbr_rh: + { + var x = [19500, 19000, 18600, 18000, 17500, 16000, + 15600, 14900, 12500, 10000, 3950]; + if (0 <= gfp.VBR_q && gfp.VBR_q <= 9) { + var a = x[gfp.VBR_q], b = x[gfp.VBR_q + 1], m = gfp.VBR_q_frac; + lowpass = linear_int(a, b, m); + } else { + lowpass = 19500; + } + break; + } + default: + { + var x = [19500, 19000, 18500, 18000, 17500, 16500, + 15500, 14500, 12500, 9500, 3950]; + if (0 <= gfp.VBR_q && gfp.VBR_q <= 9) { + var a = x[gfp.VBR_q], b = x[gfp.VBR_q + 1], m = gfp.VBR_q_frac; + lowpass = linear_int(a, b, m); + } else { + lowpass = 19500; + } + } + } + if (gfp.mode == MPEGMode.MONO + && (gfp.VBR == VbrMode.vbr_off || gfp.VBR == VbrMode.vbr_abr)) + lowpass *= 1.5; + + gfp.lowpassfreq = lowpass | 0; + } + + if (gfp.out_samplerate == 0) { + if (2 * gfp.lowpassfreq > gfp.in_samplerate) { + gfp.lowpassfreq = gfp.in_samplerate / 2; + } + gfp.out_samplerate = optimum_samplefreq(gfp.lowpassfreq | 0, + gfp.in_samplerate); + } + + gfp.lowpassfreq = Math.min(20500, gfp.lowpassfreq); + gfp.lowpassfreq = Math.min(gfp.out_samplerate / 2, gfp.lowpassfreq); + + if (gfp.VBR == VbrMode.vbr_off) { + gfp.compression_ratio = gfp.out_samplerate * 16 * gfc.channels_out + / (1.e3 * gfp.brate); + } + if (gfp.VBR == VbrMode.vbr_abr) { + gfp.compression_ratio = gfp.out_samplerate * 16 * gfc.channels_out + / (1.e3 * gfp.VBR_mean_bitrate_kbps); + } + + /* + * do not compute ReplayGain values and do not find the peak sample if + * we can't store them + */ + if (!gfp.bWriteVbrTag) { + gfp.findReplayGain = false; + gfp.decode_on_the_fly = false; + gfc.findPeakSample = false; + } + gfc.findReplayGain = gfp.findReplayGain; + gfc.decode_on_the_fly = gfp.decode_on_the_fly; + + if (gfc.decode_on_the_fly) + gfc.findPeakSample = true; + + if (gfc.findReplayGain) { + if (ga.InitGainAnalysis(gfc.rgdata, gfp.out_samplerate) == GainAnalysis.INIT_GAIN_ANALYSIS_ERROR) { + gfp.internal_flags = null; + return -6; + } + } + + if (gfc.decode_on_the_fly && !gfp.decode_only) { + if (gfc.hip != null) { + mpglib.hip_decode_exit(gfc.hip); + } + gfc.hip = mpglib.hip_decode_init(); + } + + gfc.mode_gr = gfp.out_samplerate <= 24000 ? 1 : 2; + /* + * Number of granules per frame + */ + gfp.framesize = 576 * gfc.mode_gr; + gfp.encoder_delay = Encoder.ENCDELAY; + + gfc.resample_ratio = gfp.in_samplerate / gfp.out_samplerate; + + /** + *
+         *  sample freq       bitrate     compression ratio
+         *     [kHz]      [kbps/channel]   for 16 bit input
+         *     44.1            56               12.6
+         *     44.1            64               11.025
+         *     44.1            80                8.82
+         *     22.05           24               14.7
+         *     22.05           32               11.025
+         *     22.05           40                8.82
+         *     16              16               16.0
+         *     16              24               10.667
+         * 
+ */ + /** + *
+         *  For VBR, take a guess at the compression_ratio.
+         *  For example:
+         *
+         *    VBR_q    compression     like
+         *     -        4.4         320 kbps/44 kHz
+         *   0...1      5.5         256 kbps/44 kHz
+         *     2        7.3         192 kbps/44 kHz
+         *     4        8.8         160 kbps/44 kHz
+         *     6       11           128 kbps/44 kHz
+         *     9       14.7          96 kbps
+         *
+         *  for lower bitrates, downsample with --resample
+         * 
+ */ + switch (gfp.VBR) { + case VbrMode.vbr_mt: + case VbrMode.vbr_rh: + case VbrMode.vbr_mtrh: + { + /* numbers are a bit strange, but they determine the lowpass value */ + var cmp = [5.7, 6.5, 7.3, 8.2, 10, 11.9, 13, 14, + 15, 16.5]; + gfp.compression_ratio = cmp[gfp.VBR_q]; + } + break; + case VbrMode.vbr_abr: + gfp.compression_ratio = gfp.out_samplerate * 16 * gfc.channels_out + / (1.e3 * gfp.VBR_mean_bitrate_kbps); + break; + default: + gfp.compression_ratio = gfp.out_samplerate * 16 * gfc.channels_out + / (1.e3 * gfp.brate); + break; + } + + /* + * mode = -1 (not set by user) or mode = MONO (because of only 1 input + * channel). If mode has not been set, then select J-STEREO + */ + if (gfp.mode == MPEGMode.NOT_SET) { + gfp.mode = MPEGMode.JOINT_STEREO; + } + + /* apply user driven high pass filter */ + if (gfp.highpassfreq > 0) { + gfc.highpass1 = 2. * gfp.highpassfreq; + + if (gfp.highpasswidth >= 0) + gfc.highpass2 = 2. * (gfp.highpassfreq + gfp.highpasswidth); + else + /* 0% above on default */ + gfc.highpass2 = (1 + 0.00) * 2. * gfp.highpassfreq; + + gfc.highpass1 /= gfp.out_samplerate; + gfc.highpass2 /= gfp.out_samplerate; + } else { + gfc.highpass1 = 0; + gfc.highpass2 = 0; + } + /* apply user driven low pass filter */ + if (gfp.lowpassfreq > 0) { + gfc.lowpass2 = 2. * gfp.lowpassfreq; + if (gfp.lowpasswidth >= 0) { + gfc.lowpass1 = 2. * (gfp.lowpassfreq - gfp.lowpasswidth); + if (gfc.lowpass1 < 0) /* has to be >= 0 */ + gfc.lowpass1 = 0; + } else { /* 0% below on default */ + gfc.lowpass1 = (1 - 0.00) * 2. * gfp.lowpassfreq; + } + gfc.lowpass1 /= gfp.out_samplerate; + gfc.lowpass2 /= gfp.out_samplerate; + } else { + gfc.lowpass1 = 0; + gfc.lowpass2 = 0; + } + + /**********************************************************************/ + /* compute info needed for polyphase filter (filter type==0, default) */ + /**********************************************************************/ + lame_init_params_ppflt(gfp); + /******************************************************* + * samplerate and bitrate index + *******************************************************/ + gfc.samplerate_index = SmpFrqIndex(gfp.out_samplerate, gfp); + if (gfc.samplerate_index < 0) { + gfp.internal_flags = null; + return -1; + } + + if (gfp.VBR == VbrMode.vbr_off) { + if (gfp.free_format) { + gfc.bitrate_index = 0; + } else { + gfp.brate = FindNearestBitrate(gfp.brate, gfp.version, + gfp.out_samplerate); + gfc.bitrate_index = BitrateIndex(gfp.brate, gfp.version, + gfp.out_samplerate); + if (gfc.bitrate_index <= 0) { + gfp.internal_flags = null; + return -1; + } + } + } else { + gfc.bitrate_index = 1; + } + + /* for CBR, we will write an "info" tag. */ + + if (gfp.analysis) + gfp.bWriteVbrTag = false; + + /* some file options not allowed if output is: not specified or stdout */ + if (gfc.pinfo != null) + gfp.bWriteVbrTag = false; + /* disable Xing VBR tag */ + + bs.init_bit_stream_w(gfc); + + var j = gfc.samplerate_index + (3 * gfp.version) + 6 + * (gfp.out_samplerate < 16000 ? 1 : 0); + for (var i = 0; i < Encoder.SBMAX_l + 1; i++) + gfc.scalefac_band.l[i] = qupvt.sfBandIndex[j].l[i]; + + for (var i = 0; i < Encoder.PSFB21 + 1; i++) { + var size = (gfc.scalefac_band.l[22] - gfc.scalefac_band.l[21]) + / Encoder.PSFB21; + var start = gfc.scalefac_band.l[21] + i * size; + gfc.scalefac_band.psfb21[i] = start; + } + gfc.scalefac_band.psfb21[Encoder.PSFB21] = 576; + + for (var i = 0; i < Encoder.SBMAX_s + 1; i++) + gfc.scalefac_band.s[i] = qupvt.sfBandIndex[j].s[i]; + + for (var i = 0; i < Encoder.PSFB12 + 1; i++) { + var size = (gfc.scalefac_band.s[13] - gfc.scalefac_band.s[12]) + / Encoder.PSFB12; + var start = gfc.scalefac_band.s[12] + i * size; + gfc.scalefac_band.psfb12[i] = start; + } + gfc.scalefac_band.psfb12[Encoder.PSFB12] = 192; + /* determine the mean bitrate for main data */ + if (gfp.version == 1) /* MPEG 1 */ + gfc.sideinfo_len = (gfc.channels_out == 1) ? 4 + 17 : 4 + 32; + else + /* MPEG 2 */ + gfc.sideinfo_len = (gfc.channels_out == 1) ? 4 + 9 : 4 + 17; + + if (gfp.error_protection) + gfc.sideinfo_len += 2; + + lame_init_bitstream(gfp); + + gfc.Class_ID = LAME_ID; + + { + var k; + + for (k = 0; k < 19; k++) + gfc.nsPsy.pefirbuf[k] = 700 * gfc.mode_gr * gfc.channels_out; + + if (gfp.ATHtype == -1) + gfp.ATHtype = 4; + } + + switch (gfp.VBR) { + + case VbrMode.vbr_mt: + gfp.VBR = VbrMode.vbr_mtrh; + //$FALL-THROUGH$ + case VbrMode.vbr_mtrh: + { + if (gfp.useTemporal == null) { + gfp.useTemporal = false; + /* off by default for this VBR mode */ + } + + p.apply_preset(gfp, 500 - (gfp.VBR_q * 10), 0); + /** + *
+                 *   The newer VBR code supports only a limited
+                 *     subset of quality levels:
+                 *     9-5=5 are the same, uses x^3/4 quantization
+                 *   4-0=0 are the same  5 plus best huffman divide code
+                 * 
+ */ + if (gfp.quality < 0) + gfp.quality = LAME_DEFAULT_QUALITY; + if (gfp.quality < 5) + gfp.quality = 0; + if (gfp.quality > 5) + gfp.quality = 5; + + gfc.PSY.mask_adjust = gfp.maskingadjust; + gfc.PSY.mask_adjust_short = gfp.maskingadjust_short; + + /* + * sfb21 extra only with MPEG-1 at higher sampling rates + */ + if (gfp.experimentalY) + gfc.sfb21_extra = false; + else + gfc.sfb21_extra = (gfp.out_samplerate > 44000); + + gfc.iteration_loop = new VBRNewIterationLoop(qu); + break; + + } + case VbrMode.vbr_rh: + { + + p.apply_preset(gfp, 500 - (gfp.VBR_q * 10), 0); + + gfc.PSY.mask_adjust = gfp.maskingadjust; + gfc.PSY.mask_adjust_short = gfp.maskingadjust_short; + + /* + * sfb21 extra only with MPEG-1 at higher sampling rates + */ + if (gfp.experimentalY) + gfc.sfb21_extra = false; + else + gfc.sfb21_extra = (gfp.out_samplerate > 44000); + + /* + * VBR needs at least the output of GPSYCHO, so we have to garantee + * that by setting a minimum quality level, actually level 6 does + * it. down to level 6 + */ + if (gfp.quality > 6) + gfp.quality = 6; + + if (gfp.quality < 0) + gfp.quality = LAME_DEFAULT_QUALITY; + + gfc.iteration_loop = new VBROldIterationLoop(qu); + break; + } + + default: /* cbr/abr */ + { + var vbrmode; + + /* + * no sfb21 extra with CBR code + */ + gfc.sfb21_extra = false; + + if (gfp.quality < 0) + gfp.quality = LAME_DEFAULT_QUALITY; + + vbrmode = gfp.VBR; + if (vbrmode == VbrMode.vbr_off) + gfp.VBR_mean_bitrate_kbps = gfp.brate; + /* second, set parameters depending on bitrate */ + p.apply_preset(gfp, gfp.VBR_mean_bitrate_kbps, 0); + gfp.VBR = vbrmode; + + gfc.PSY.mask_adjust = gfp.maskingadjust; + gfc.PSY.mask_adjust_short = gfp.maskingadjust_short; + + if (vbrmode == VbrMode.vbr_off) { + gfc.iteration_loop = new CBRNewIterationLoop(qu); + } else { + gfc.iteration_loop = new ABRIterationLoop(qu); + } + break; + } + } + /* initialize default values common for all modes */ + + if (gfp.VBR != VbrMode.vbr_off) { /* choose a min/max bitrate for VBR */ + /* if the user didn't specify VBR_max_bitrate: */ + gfc.VBR_min_bitrate = 1; + /* + * default: allow 8 kbps (MPEG-2) or 32 kbps (MPEG-1) + */ + gfc.VBR_max_bitrate = 14; + /* + * default: allow 160 kbps (MPEG-2) or 320 kbps (MPEG-1) + */ + if (gfp.out_samplerate < 16000) + gfc.VBR_max_bitrate = 8; + /* default: allow 64 kbps (MPEG-2.5) */ + if (gfp.VBR_min_bitrate_kbps != 0) { + gfp.VBR_min_bitrate_kbps = FindNearestBitrate( + gfp.VBR_min_bitrate_kbps, gfp.version, + gfp.out_samplerate); + gfc.VBR_min_bitrate = BitrateIndex(gfp.VBR_min_bitrate_kbps, + gfp.version, gfp.out_samplerate); + if (gfc.VBR_min_bitrate < 0) + return -1; + } + if (gfp.VBR_max_bitrate_kbps != 0) { + gfp.VBR_max_bitrate_kbps = FindNearestBitrate( + gfp.VBR_max_bitrate_kbps, gfp.version, + gfp.out_samplerate); + gfc.VBR_max_bitrate = BitrateIndex(gfp.VBR_max_bitrate_kbps, + gfp.version, gfp.out_samplerate); + if (gfc.VBR_max_bitrate < 0) + return -1; + } + gfp.VBR_min_bitrate_kbps = Tables.bitrate_table[gfp.version][gfc.VBR_min_bitrate]; + gfp.VBR_max_bitrate_kbps = Tables.bitrate_table[gfp.version][gfc.VBR_max_bitrate]; + gfp.VBR_mean_bitrate_kbps = Math.min( + Tables.bitrate_table[gfp.version][gfc.VBR_max_bitrate], + gfp.VBR_mean_bitrate_kbps); + gfp.VBR_mean_bitrate_kbps = Math.max( + Tables.bitrate_table[gfp.version][gfc.VBR_min_bitrate], + gfp.VBR_mean_bitrate_kbps); + } + + /* just another daily changing developer switch */ + if (gfp.tune) { + gfc.PSY.mask_adjust += gfp.tune_value_a; + gfc.PSY.mask_adjust_short += gfp.tune_value_a; + } + + /* initialize internal qval settings */ + lame_init_qval(gfp); + /* + * automatic ATH adjustment on + */ + if (gfp.athaa_type < 0) + gfc.ATH.useAdjust = 3; + else + gfc.ATH.useAdjust = gfp.athaa_type; + + /* initialize internal adaptive ATH settings -jd */ + gfc.ATH.aaSensitivityP = Math.pow(10.0, gfp.athaa_sensitivity + / -10.0); + + if (gfp.short_blocks == null) { + gfp.short_blocks = ShortBlock.short_block_allowed; + } + + /* + * Note Jan/2003: Many hardware decoders cannot handle short blocks in + * regular stereo mode unless they are coupled (same type in both + * channels) it is a rare event (1 frame per min. or so) that LAME would + * use uncoupled short blocks, so lets turn them off until we decide how + * to handle this. No other encoders allow uncoupled short blocks, even + * though it is in the standard. + */ + /* + * rh 20040217: coupling makes no sense for mono and dual-mono streams + */ + if (gfp.short_blocks == ShortBlock.short_block_allowed + && (gfp.mode == MPEGMode.JOINT_STEREO || gfp.mode == MPEGMode.STEREO)) { + gfp.short_blocks = ShortBlock.short_block_coupled; + } + + if (gfp.quant_comp < 0) + gfp.quant_comp = 1; + if (gfp.quant_comp_short < 0) + gfp.quant_comp_short = 0; + + if (gfp.msfix < 0) + gfp.msfix = 0; + + /* select psychoacoustic model */ + gfp.exp_nspsytune = gfp.exp_nspsytune | 1; + + if (gfp.internal_flags.nsPsy.attackthre < 0) + gfp.internal_flags.nsPsy.attackthre = PsyModel.NSATTACKTHRE; + if (gfp.internal_flags.nsPsy.attackthre_s < 0) + gfp.internal_flags.nsPsy.attackthre_s = PsyModel.NSATTACKTHRE_S; + + + if (gfp.scale < 0) + gfp.scale = 1; + + if (gfp.ATHtype < 0) + gfp.ATHtype = 4; + + if (gfp.ATHcurve < 0) + gfp.ATHcurve = 4; + + if (gfp.athaa_loudapprox < 0) + gfp.athaa_loudapprox = 2; + + if (gfp.interChRatio < 0) + gfp.interChRatio = 0; + + if (gfp.useTemporal == null) + gfp.useTemporal = true; + /* on by default */ + + /* + * padding method as described in + * "MPEG-Layer3 / Bitstream Syntax and Decoding" by Martin Sieler, Ralph + * Sperschneider + * + * note: there is no padding for the very first frame + * + * Robert Hegemann 2000-06-22 + */ + gfc.slot_lag = gfc.frac_SpF = 0; + if (gfp.VBR == VbrMode.vbr_off) + gfc.slot_lag = gfc.frac_SpF = (((gfp.version + 1) * 72000 * gfp.brate) % gfp.out_samplerate) | 0; + + qupvt.iteration_init(gfp); + psy.psymodel_init(gfp); + return 0; + } + + function update_inbuffer_size(gfc, nsamples) { + if (gfc.in_buffer_0 == null || gfc.in_buffer_nsamples < nsamples) { + gfc.in_buffer_0 = new_float(nsamples); + gfc.in_buffer_1 = new_float(nsamples); + gfc.in_buffer_nsamples = nsamples; + } + } + + this.lame_encode_flush = function (gfp, mp3buffer, mp3bufferPos, mp3buffer_size) { + var gfc = gfp.internal_flags; + var buffer = new_short_n([2, 1152]); + var imp3 = 0, mp3count, mp3buffer_size_remaining; + + /* + * we always add POSTDELAY=288 padding to make sure granule with real + * data can be complety decoded (because of 50% overlap with next + * granule + */ + var end_padding; + var frames_left; + var samples_to_encode = gfc.mf_samples_to_encode - Encoder.POSTDELAY; + var mf_needed = calcNeeded(gfp); + + /* Was flush already called? */ + if (gfc.mf_samples_to_encode < 1) { + return 0; + } + mp3count = 0; + + if (gfp.in_samplerate != gfp.out_samplerate) { + /* + * delay due to resampling; needs to be fixed, if resampling code + * gets changed + */ + samples_to_encode += 16. * gfp.out_samplerate / gfp.in_samplerate; + } + end_padding = gfp.framesize - (samples_to_encode % gfp.framesize); + if (end_padding < 576) + end_padding += gfp.framesize; + gfp.encoder_padding = end_padding; + + frames_left = (samples_to_encode + end_padding) / gfp.framesize; + + /* + * send in a frame of 0 padding until all internal sample buffers are + * flushed + */ + while (frames_left > 0 && imp3 >= 0) { + var bunch = mf_needed - gfc.mf_size; + var frame_num = gfp.frameNum; + + bunch *= gfp.in_samplerate; + bunch /= gfp.out_samplerate; + if (bunch > 1152) + bunch = 1152; + if (bunch < 1) + bunch = 1; + + mp3buffer_size_remaining = mp3buffer_size - mp3count; + + /* if user specifed buffer size = 0, dont check size */ + if (mp3buffer_size == 0) + mp3buffer_size_remaining = 0; + + imp3 = this.lame_encode_buffer(gfp, buffer[0], buffer[1], bunch, + mp3buffer, mp3bufferPos, mp3buffer_size_remaining); + + mp3bufferPos += imp3; + mp3count += imp3; + frames_left -= (frame_num != gfp.frameNum) ? 1 : 0; + } + /* + * Set gfc.mf_samples_to_encode to 0, so we may detect and break loops + * calling it more than once in a row. + */ + gfc.mf_samples_to_encode = 0; + + if (imp3 < 0) { + /* some type of fatal error */ + return imp3; + } + + mp3buffer_size_remaining = mp3buffer_size - mp3count; + /* if user specifed buffer size = 0, dont check size */ + if (mp3buffer_size == 0) + mp3buffer_size_remaining = 0; + + /* mp3 related stuff. bit buffer might still contain some mp3 data */ + bs.flush_bitstream(gfp); + imp3 = bs.copy_buffer(gfc, mp3buffer, mp3bufferPos, + mp3buffer_size_remaining, 1); + if (imp3 < 0) { + /* some type of fatal error */ + return imp3; + } + mp3bufferPos += imp3; + mp3count += imp3; + mp3buffer_size_remaining = mp3buffer_size - mp3count; + /* if user specifed buffer size = 0, dont check size */ + if (mp3buffer_size == 0) + mp3buffer_size_remaining = 0; + + if (gfp.write_id3tag_automatic) { + /* write a id3 tag to the bitstream */ + id3.id3tag_write_v1(gfp); + + imp3 = bs.copy_buffer(gfc, mp3buffer, mp3bufferPos, + mp3buffer_size_remaining, 0); + + if (imp3 < 0) { + return imp3; + } + mp3count += imp3; + } + return mp3count; + }; + + this.lame_encode_buffer = function (gfp, buffer_l, buffer_r, nsamples, mp3buf, mp3bufPos, mp3buf_size) { + var gfc = gfp.internal_flags; + var in_buffer = [null, null]; + + if (gfc.Class_ID != LAME_ID) + return -3; + + if (nsamples == 0) + return 0; + + update_inbuffer_size(gfc, nsamples); + + in_buffer[0] = gfc.in_buffer_0; + in_buffer[1] = gfc.in_buffer_1; + + /* make a copy of input buffer, changing type to sample_t */ + for (var i = 0; i < nsamples; i++) { + in_buffer[0][i] = buffer_l[i]; + if (gfc.channels_in > 1) + in_buffer[1][i] = buffer_r[i]; + } + + return lame_encode_buffer_sample(gfp, in_buffer[0], in_buffer[1], + nsamples, mp3buf, mp3bufPos, mp3buf_size); + } + + function calcNeeded(gfp) { + var mf_needed = Encoder.BLKSIZE + gfp.framesize - Encoder.FFTOFFSET; + /* + * amount needed for FFT + */ + mf_needed = Math.max(mf_needed, 512 + gfp.framesize - 32); + + return mf_needed; + } + + function lame_encode_buffer_sample(gfp, buffer_l, buffer_r, nsamples, mp3buf, mp3bufPos, mp3buf_size) { + var gfc = gfp.internal_flags; + var mp3size = 0, ret, i, ch, mf_needed; + var mp3out; + var mfbuf = [null, null]; + var in_buffer = [null, null]; + + if (gfc.Class_ID != LAME_ID) + return -3; + + if (nsamples == 0) + return 0; + + /* copy out any tags that may have been written into bitstream */ + mp3out = bs.copy_buffer(gfc, mp3buf, mp3bufPos, mp3buf_size, 0); + if (mp3out < 0) + return mp3out; + /* not enough buffer space */ + mp3bufPos += mp3out; + mp3size += mp3out; + + in_buffer[0] = buffer_l; + in_buffer[1] = buffer_r; + + /* Apply user defined re-scaling */ + + /* user selected scaling of the samples */ + if (BitStream.NEQ(gfp.scale, 0) && BitStream.NEQ(gfp.scale, 1.0)) { + for (i = 0; i < nsamples; ++i) { + in_buffer[0][i] *= gfp.scale; + if (gfc.channels_out == 2) + in_buffer[1][i] *= gfp.scale; + } + } + + /* user selected scaling of the channel 0 (left) samples */ + if (BitStream.NEQ(gfp.scale_left, 0) + && BitStream.NEQ(gfp.scale_left, 1.0)) { + for (i = 0; i < nsamples; ++i) { + in_buffer[0][i] *= gfp.scale_left; + } + } + + /* user selected scaling of the channel 1 (right) samples */ + if (BitStream.NEQ(gfp.scale_right, 0) + && BitStream.NEQ(gfp.scale_right, 1.0)) { + for (i = 0; i < nsamples; ++i) { + in_buffer[1][i] *= gfp.scale_right; + } + } + + /* Downsample to Mono if 2 channels in and 1 channel out */ + if (gfp.num_channels == 2 && gfc.channels_out == 1) { + for (i = 0; i < nsamples; ++i) { + in_buffer[0][i] = 0.5 * ( in_buffer[0][i] + in_buffer[1][i]); + in_buffer[1][i] = 0.0; + } + } + + mf_needed = calcNeeded(gfp); + + mfbuf[0] = gfc.mfbuf[0]; + mfbuf[1] = gfc.mfbuf[1]; + + var in_bufferPos = 0; + while (nsamples > 0) { + var in_buffer_ptr = [null, null]; + var n_in = 0; + /* number of input samples processed with fill_buffer */ + var n_out = 0; + /* number of samples output with fill_buffer */ + /* n_in <> n_out if we are resampling */ + + in_buffer_ptr[0] = in_buffer[0]; + in_buffer_ptr[1] = in_buffer[1]; + /* copy in new samples into mfbuf, with resampling */ + var inOut = new InOut(); + fill_buffer(gfp, mfbuf, in_buffer_ptr, in_bufferPos, nsamples, + inOut); + n_in = inOut.n_in; + n_out = inOut.n_out; + + /* compute ReplayGain of resampled input if requested */ + if (gfc.findReplayGain && !gfc.decode_on_the_fly) + if (ga.AnalyzeSamples(gfc.rgdata, mfbuf[0], gfc.mf_size, + mfbuf[1], gfc.mf_size, n_out, gfc.channels_out) == GainAnalysis.GAIN_ANALYSIS_ERROR) + return -6; + + /* update in_buffer counters */ + nsamples -= n_in; + in_bufferPos += n_in; + if (gfc.channels_out == 2) + ;// in_bufferPos += n_in; + + /* update mfbuf[] counters */ + gfc.mf_size += n_out; + + /* + * lame_encode_flush may have set gfc.mf_sample_to_encode to 0 so we + * have to reinitialize it here when that happened. + */ + if (gfc.mf_samples_to_encode < 1) { + gfc.mf_samples_to_encode = Encoder.ENCDELAY + Encoder.POSTDELAY; + } + gfc.mf_samples_to_encode += n_out; + + if (gfc.mf_size >= mf_needed) { + /* encode the frame. */ + /* mp3buf = pointer to current location in buffer */ + /* mp3buf_size = size of original mp3 output buffer */ + /* = 0 if we should not worry about the */ + /* buffer size because calling program is */ + /* to lazy to compute it */ + /* mp3size = size of data written to buffer so far */ + /* mp3buf_size-mp3size = amount of space avalable */ + + var buf_size = mp3buf_size - mp3size; + if (mp3buf_size == 0) + buf_size = 0; + + ret = lame_encode_frame(gfp, mfbuf[0], mfbuf[1], mp3buf, + mp3bufPos, buf_size); + + if (ret < 0) + return ret; + mp3bufPos += ret; + mp3size += ret; + + /* shift out old samples */ + gfc.mf_size -= gfp.framesize; + gfc.mf_samples_to_encode -= gfp.framesize; + for (ch = 0; ch < gfc.channels_out; ch++) + for (i = 0; i < gfc.mf_size; i++) + mfbuf[ch][i] = mfbuf[ch][i + gfp.framesize]; + } + } + + return mp3size; + } + + function lame_encode_frame(gfp, inbuf_l, inbuf_r, mp3buf, mp3bufPos, mp3buf_size) { + var ret = self.enc.lame_encode_mp3_frame(gfp, inbuf_l, inbuf_r, mp3buf, + mp3bufPos, mp3buf_size); + gfp.frameNum++; + return ret; + } + + function InOut() { + this.n_in = 0; + this.n_out = 0; + } + + + function NumUsed() { + this.num_used = 0; + } + + /** + * Greatest common divisor. + *

+ * Joint work of Euclid and M. Hendry + */ + function gcd(i, j) { + return j != 0 ? gcd(j, i % j) : i; + } + + /** + * Resampling via FIR filter, blackman window. + */ + function blackman(x, fcn, l) { + /* + * This algorithm from: SIGNAL PROCESSING ALGORITHMS IN FORTRAN AND C + * S.D. Stearns and R.A. David, Prentice-Hall, 1992 + */ + var wcn = (Math.PI * fcn); + + x /= l; + if (x < 0) + x = 0; + if (x > 1) + x = 1; + var x2 = x - .5; + + var bkwn = 0.42 - 0.5 * Math.cos(2 * x * Math.PI) + 0.08 * Math.cos(4 * x * Math.PI); + if (Math.abs(x2) < 1e-9) + return (wcn / Math.PI); + else + return (bkwn * Math.sin(l * wcn * x2) / (Math.PI * l * x2)); + } + + function fill_buffer_resample(gfp, outbuf, outbufPos, desired_len, inbuf, in_bufferPos, len, num_used, ch) { + var gfc = gfp.internal_flags; + var i, j = 0, k; + /* number of convolution functions to pre-compute */ + var bpc = gfp.out_samplerate + / gcd(gfp.out_samplerate, gfp.in_samplerate); + if (bpc > LameInternalFlags.BPC) + bpc = LameInternalFlags.BPC; + + var intratio = (Math.abs(gfc.resample_ratio + - Math.floor(.5 + gfc.resample_ratio)) < .0001) ? 1 : 0; + var fcn = 1.00 / gfc.resample_ratio; + if (fcn > 1.00) + fcn = 1.00; + var filter_l = 31; + if (0 == filter_l % 2) + --filter_l; + /* must be odd */ + filter_l += intratio; + /* unless resample_ratio=int, it must be even */ + + var BLACKSIZE = filter_l + 1; + /* size of data needed for FIR */ + + if (gfc.fill_buffer_resample_init == 0) { + gfc.inbuf_old[0] = new_float(BLACKSIZE); + gfc.inbuf_old[1] = new_float(BLACKSIZE); + for (i = 0; i <= 2 * bpc; ++i) + gfc.blackfilt[i] = new_float(BLACKSIZE); + + gfc.itime[0] = 0; + gfc.itime[1] = 0; + + /* precompute blackman filter coefficients */ + for (j = 0; j <= 2 * bpc; j++) { + var sum = 0.; + var offset = (j - bpc) / (2. * bpc); + for (i = 0; i <= filter_l; i++) + sum += gfc.blackfilt[j][i] = blackman(i - offset, fcn, + filter_l); + for (i = 0; i <= filter_l; i++) + gfc.blackfilt[j][i] /= sum; + } + gfc.fill_buffer_resample_init = 1; + } + + var inbuf_old = gfc.inbuf_old[ch]; + + /* time of j'th element in inbuf = itime + j/ifreq; */ + /* time of k'th element in outbuf = j/ofreq */ + for (k = 0; k < desired_len; k++) { + var time0; + var joff; + + time0 = k * gfc.resample_ratio; + /* time of k'th output sample */ + j = 0 | Math.floor(time0 - gfc.itime[ch]); + + /* check if we need more input data */ + if ((filter_l + j - filter_l / 2) >= len) + break; + + /* blackman filter. by default, window centered at j+.5(filter_l%2) */ + /* but we want a window centered at time0. */ + var offset = (time0 - gfc.itime[ch] - (j + .5 * (filter_l % 2))); + + /* find the closest precomputed window for this offset: */ + joff = 0 | Math.floor((offset * 2 * bpc) + bpc + .5); + var xvalue = 0.; + for (i = 0; i <= filter_l; ++i) { + var j2 = i + j - filter_l / 2; + var y; + y = (j2 < 0) ? inbuf_old[BLACKSIZE + j2] : inbuf[in_bufferPos + + j2]; + xvalue += y * gfc.blackfilt[joff][i]; + } + outbuf[outbufPos + k] = xvalue; + } + + /* k = number of samples added to outbuf */ + /* last k sample used data from [j-filter_l/2,j+filter_l-filter_l/2] */ + + /* how many samples of input data were used: */ + num_used.num_used = Math.min(len, filter_l + j - filter_l / 2); + + /* + * adjust our input time counter. Incriment by the number of samples + * used, then normalize so that next output sample is at time 0, next + * input buffer is at time itime[ch] + */ + gfc.itime[ch] += num_used.num_used - k * gfc.resample_ratio; + + /* save the last BLACKSIZE samples into the inbuf_old buffer */ + if (num_used.num_used >= BLACKSIZE) { + for (i = 0; i < BLACKSIZE; i++) + inbuf_old[i] = inbuf[in_bufferPos + num_used.num_used + i + - BLACKSIZE]; + } else { + /* shift in num_used.num_used samples into inbuf_old */ + var n_shift = BLACKSIZE - num_used.num_used; + /* + * number of samples to + * shift + */ + + /* + * shift n_shift samples by num_used.num_used, to make room for the + * num_used new samples + */ + for (i = 0; i < n_shift; ++i) + inbuf_old[i] = inbuf_old[i + num_used.num_used]; + + /* shift in the num_used.num_used samples */ + for (j = 0; i < BLACKSIZE; ++i, ++j) + inbuf_old[i] = inbuf[in_bufferPos + j]; + + } + return k; + /* return the number samples created at the new samplerate */ + } + + function fill_buffer(gfp, mfbuf, in_buffer, in_bufferPos, nsamples, io) { + var gfc = gfp.internal_flags; + + /* copy in new samples into mfbuf, with resampling if necessary */ + if ((gfc.resample_ratio < .9999) || (gfc.resample_ratio > 1.0001)) { + for (var ch = 0; ch < gfc.channels_out; ch++) { + var numUsed = new NumUsed(); + io.n_out = fill_buffer_resample(gfp, mfbuf[ch], gfc.mf_size, + gfp.framesize, in_buffer[ch], in_bufferPos, nsamples, + numUsed, ch); + io.n_in = numUsed.num_used; + } + } else { + io.n_out = Math.min(gfp.framesize, nsamples); + io.n_in = io.n_out; + for (var i = 0; i < io.n_out; ++i) { + mfbuf[0][gfc.mf_size + i] = in_buffer[0][in_bufferPos + i]; + if (gfc.channels_out == 2) + mfbuf[1][gfc.mf_size + i] = in_buffer[1][in_bufferPos + i]; + } + } + } + +} + + + +function GetAudio() { + var parse; + var mpg; + + this.setModules = function (parse2, mpg2) { + parse = parse2; + mpg = mpg2; + } +} + + +function Parse() { + var ver; + var id3; + var pre; + + this.setModules = function (ver2, id32, pre2) { + ver = ver2; + id3 = id32; + pre = pre2; + } +} + +function MPGLib() { +} + +function ID3Tag() { + var bits; + var ver; + + this.setModules = function (_bits, _ver) { + bits = _bits; + ver = _ver; + } +} + +function Mp3Encoder(channels, samplerate, kbps) { + if (arguments.length != 3) { + console.error('WARN: Mp3Encoder(channels, samplerate, kbps) not specified'); + channels = 1; + samplerate = 44100; + kbps = 128; + } + var lame = new Lame(); + var gaud = new GetAudio(); + var ga = new GainAnalysis(); + var bs = new BitStream(); + var p = new Presets(); + var qupvt = new QuantizePVT(); + var qu = new Quantize(); + var vbr = new VBRTag(); + var ver = new Version(); + var id3 = new ID3Tag(); + var rv = new Reservoir(); + var tak = new Takehiro(); + var parse = new Parse(); + var mpg = new MPGLib(); + + lame.setModules(ga, bs, p, qupvt, qu, vbr, ver, id3, mpg); + bs.setModules(ga, mpg, ver, vbr); + id3.setModules(bs, ver); + p.setModules(lame); + qu.setModules(bs, rv, qupvt, tak); + qupvt.setModules(tak, rv, lame.enc.psy); + rv.setModules(bs); + tak.setModules(qupvt); + vbr.setModules(lame, bs, ver); + gaud.setModules(parse, mpg); + parse.setModules(ver, id3, p); + + var gfp = lame.lame_init(); + + gfp.num_channels = channels; + gfp.in_samplerate = samplerate; + gfp.brate = kbps; + gfp.mode = MPEGMode.STEREO; + gfp.quality = 3; + gfp.bWriteVbrTag = false; + gfp.disable_reservoir = true; + gfp.write_id3tag_automatic = false; + + var retcode = lame.lame_init_params(gfp); + var maxSamples = 1152; + var mp3buf_size = 0 | (1.25 * maxSamples + 7200); + var mp3buf = new_byte(mp3buf_size); + + this.encodeBuffer = function (left, right) { + if (channels == 1) { + right = left; + } + if (left.length > maxSamples) { + maxSamples = left.length; + mp3buf_size = 0 | (1.25 * maxSamples + 7200); + mp3buf = new_byte(mp3buf_size); + } + + var _sz = lame.lame_encode_buffer(gfp, left, right, left.length, mp3buf, 0, mp3buf_size); + return new Int8Array(mp3buf.subarray(0, _sz)); + }; + + this.flush = function () { + var _sz = lame.lame_encode_flush(gfp, mp3buf, 0, mp3buf_size); + return new Int8Array(mp3buf.subarray(0, _sz)); + }; +} + +function WavHeader() { + this.dataOffset = 0; + this.dataLen = 0; + this.channels = 0; + this.sampleRate = 0; +} + +function fourccToInt(fourcc) { + return fourcc.charCodeAt(0) << 24 | fourcc.charCodeAt(1) << 16 | fourcc.charCodeAt(2) << 8 | fourcc.charCodeAt(3); +} + +WavHeader.RIFF = fourccToInt("RIFF"); +WavHeader.WAVE = fourccToInt("WAVE"); +WavHeader.fmt_ = fourccToInt("fmt "); +WavHeader.data = fourccToInt("data"); + +WavHeader.readHeader = function (dataView) { + var w = new WavHeader(); + + var header = dataView.getUint32(0, false); + if (WavHeader.RIFF != header) { + return; + } + var fileLen = dataView.getUint32(4, true); + if (WavHeader.WAVE != dataView.getUint32(8, false)) { + return; + } + if (WavHeader.fmt_ != dataView.getUint32(12, false)) { + return; + } + var fmtLen = dataView.getUint32(16, true); + var pos = 16 + 4; + switch (fmtLen) { + case 16: + case 18: + w.channels = dataView.getUint16(pos + 2, true); + w.sampleRate = dataView.getUint32(pos + 4, true); + break; + default: + throw 'extended fmt chunk not implemented'; + } + pos += fmtLen; + var data = WavHeader.data; + var len = 0; + while (data != header) { + header = dataView.getUint32(pos, false); + len = dataView.getUint32(pos + 4, true); + if (data == header) { + break; + } + pos += (len + 8); + } + w.dataLen = len; + w.dataOffset = pos + 8; + return w; +}; + +L3Side.SFBMAX = (Encoder.SBMAX_s * 3); +//testFullLength(); +lamejs.Mp3Encoder = Mp3Encoder; +lamejs.WavHeader = WavHeader; +} +//fs=require('fs'); +lamejs(); + + + + + +var sample_rate = 44100; +var kbps = 128; +var channels = 1; +var mp3encoder = null; + +var samples_left = null; +var samples_right = null; +var first_buffer = true; + +onmessage = function( ev ) { + if (!ev.data) return ; + + if (ev.data.sample_rate) { + sample_rate = ev.data.sample_rate / 1; + kbps = ev.data.kbps / 1; + channels = ev.data.channels / 1; + + return ; + } + + if (first_buffer) { + samples_left = new Int16Array( ev.data ); + first_buffer = false; + + if (channels > 1) return ; + } + + if (ev.data && channels > 1) { + samples_right = new Int16Array( ev.data ); + } + + if (!mp3encoder) + mp3encoder = new lamejs.Mp3Encoder (channels, sample_rate, kbps); + + var sampleBlockSize = 1152 * 2; + var sampleChunk; + var mp3Data = []; + var percentage = 0; + + var sampleChunkLeft = null; + var sampleChunkRight = null; + + for(var i = 0; i < samples_left.length; i += sampleBlockSize) { + sampleChunkLeft = samples_left.subarray ( i, i + sampleBlockSize ); + + if (samples_right) + sampleChunkRight = samples_right.subarray ( i, i + sampleBlockSize ); + + var mp3buf = mp3encoder.encodeBuffer (sampleChunkLeft, sampleChunkRight); + + if ( (((i / samples_left.length) * 100) >> 0) > percentage ) { + percentage = (((i / samples_left.length) * 100) >> 0); + postMessage ({ percentage: percentage }); + } + + if(mp3buf.length > 0) { + mp3Data.push ( mp3buf ); + } + } + mp3buf = mp3encoder.flush( ); + if(mp3buf.length > 0) { + mp3Data.push ( mp3buf ); + } + + + var blob = new Blob (mp3Data, {type:'audio/mp3'}); + postMessage( blob ); + // postMessage( mp3Data ); +} \ No newline at end of file diff --git a/audiomass-editor/src/libflac.js b/audiomass-editor/src/libflac.js new file mode 100644 index 0000000..70960f3 --- /dev/null +++ b/audiomass-editor/src/libflac.js @@ -0,0 +1 @@ +var Module=void 0!==Module?Module:{};((e,r)=>{"function"==typeof define&&define.amd?define(["module","require"],r.bind(null,e)):"object"==typeof module&&module.exports?r("undefined"!=typeof process&&process&&process.env?process.env:e,module,module.require):e.Flac=r(e)})("undefined"!=typeof self?self:"undefined"!=typeof window?window:this,function(a,N,G){var V,e,y=y||{},Y=!1,r=(y.onRuntimeInitialized=function(){Y=!0,S?O("ready",[{type:"ready",target:S}],!0):setTimeout(function(){O("ready",[{type:"ready",target:S}],!0)},0)},a&&a.FLAC_SCRIPT_LOCATION&&(y.locateFile=function(e){var r=a.FLAC_SCRIPT_LOCATION||"";return r[e]||(r+=r&&!/\/$/.test(r)?"/":"")+e},t=function(e){var r;return n?(k((r=(r=i(e,!0)).buffer?r:new Uint8Array(r)).buffer),r):new Promise(function(r,a){var i=new XMLHttpRequest;i.responseType="arraybuffer",i.addEventListener("load",function(e){r(i.response)}),i.addEventListener("error",function(e){a(e)}),i.open("GET",e),i.send()})}),a&&"function"==typeof a.fetch&&(V=a.fetch,a.fetch=function(a){return V.apply(null,arguments).catch(function(r){try{var e=t(a);return e&&e.catch&&e.catch(function(e){throw r}),e}catch(e){throw r}})}),{});for(e in y)y.hasOwnProperty(e)&&(r[e]=y[e]);var i,t,R,T,U=!1,c=!1,n=!1,U="object"==typeof window,c="function"==typeof importScripts,n="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,x=!U&&!n&&!c,f="";n?(f=c?G("path").dirname(f)+"/":__dirname+"/",i=function(e,r){var a=M(e);return a?r?a:a.toString():(R=R||G("fs"),e=(T=T||G("path")).normalize(e),R.readFileSync(e,r?null:"utf8"))},t=function(e){e=i(e,!0);return k((e=e.buffer?e:new Uint8Array(e)).buffer),e},1{var e=new ArrayBuffer(8),_=new Int32Array(e),c=new Float32Array(e),s=new Float64Array(e);function d(e,r){_[e]=r}function m(){return s[0]}function g(e){s[0]=e}for(var i,u,b,Q2,s0,p,P2,O2,C,S2,N2,m0,G2,V2,Y2,g0,v,A0,k,w,y,F,B,D,L,I,R2,M,Q,T2,e=new Uint8Array(f.buffer),P=new Uint8Array(123),O=25;0<=O;--O)P[48+O]=52+O,P[65+O]=O,P[97+O]=26+O;function r(e,r,a){for(var i,t,n=0,f=r,o=a.length,s=r+(3*o>>2)-("="==a[o-2])-("="==a[o-1]);n>4,f>2),f>2],i=P2[(r|=0)+4>>2];return 0|((0|(e=P2[e>>2]))==(0|(r=P2[r>>2]))&(0|a)==(0|i)?0:(0|a)==(0|i)&e>>>0>>0|a>>>0>>0?-1:1)},Q2[2]=function(e){return 0|y(P2[(e|=0)+60>>2])},Q2[3]=function(e,r,a){e|=0,a|=0;var i,t,n,f=0;P2[16+(R2=n=R2-32|0)>>2]=r|=0,f=P2[e+48>>2],P2[20+n>>2]=a-(0!=(0|f)),i=P2[e+44>>2],P2[28+n>>2]=f,P2[24+n>>2]=i;e:{r:{if(M0(0|F(P2[e+60>>2],16+n|0,2,12+n|0)))a=P2[12+n>>2]=-1;else{if(0<(0|(f=P2[12+n>>2])))break r;a=f}P2[e>>2]=P2[e>>2]|48&a^16;break e}f>>>0<=(t=P2[20+n>>2])>>>0?a=f:(i=P2[e+44>>2],P2[e+4>>2]=i,P2[e+8>>2]=i+(f-t|0),P2[e+48>>2]&&(P2[e+4>>2]=i+1,s0[(r+a|0)-1|0]=O2[0|i]))}return R2=32+n|0,0|a},Q2[4]=function(e,r,a,i){var t;return R2=t=R2-16|0,e=M0(0|I(P2[(e|=0)+60>>2],0|(r|=0),0|(a|=0),255&(i|=0),8+t|0))?(P2[8+t>>2]=-1,r=P2[12+t>>2]=-1):(r=P2[12+t>>2],P2[8+t>>2]),R2=16+t|0,T2=r,0|e},Q2[5]=function(e,r,a,i,t,n){e|=0,r|=0,a|=0,t|=0,n|=0;var f,o,s=0,c=0,u=0,b=0,A=0,k=0,l=0,_=0,d=0,m=0,g=0,p=0,w=0,h=0,v=0,y=0,C=0,E=0,F=0,B=0,D=0,L=0,I=0;if(13<=(i|=0)>>>0){if(!((0|r)<1))for(p=i+-13|0;;){e:switch((i=u=k=g=c=_=b=d=A=l=m=w=v=h=C=y=F=E=D=B=0)|p){case 19:B=G2(P2[((s<<2)+n|0)-128>>2],P2[a+124>>2]);case 18:D=G2(P2[((s<<2)+n|0)-124>>2],P2[a+120>>2])+B|0;case 17:E=G2(P2[((s<<2)+n|0)-120>>2],P2[a+116>>2])+D|0;case 16:F=G2(P2[((s<<2)+n|0)-116>>2],P2[a+112>>2])+E|0;case 15:y=G2(P2[((s<<2)+n|0)-112>>2],P2[a+108>>2])+F|0;case 14:C=G2(P2[((s<<2)+n|0)-108>>2],P2[a+104>>2])+y|0;case 13:h=G2(P2[((s<<2)+n|0)-104>>2],P2[a+100>>2])+C|0;case 12:v=G2(P2[((s<<2)+n|0)-100>>2],P2[a+96>>2])+h|0;case 11:w=G2(P2[((s<<2)+n|0)-96>>2],P2[a+92>>2])+v|0;case 10:m=G2(P2[((s<<2)+n|0)-92>>2],P2[a+88>>2])+w|0;case 9:l=G2(P2[((s<<2)+n|0)-88>>2],P2[a+84>>2])+m|0;case 8:A=G2(P2[((s<<2)+n|0)-84>>2],P2[a+80>>2])+l|0;case 7:d=G2(P2[((s<<2)+n|0)-80>>2],P2[a+76>>2])+A|0;case 6:b=G2(P2[((s<<2)+n|0)-76>>2],P2[a+72>>2])+d|0;case 5:_=G2(P2[((s<<2)+n|0)-72>>2],P2[a+68>>2])+b|0;case 4:c=G2(P2[((s<<2)+n|0)-68>>2],P2[a+64>>2])+_|0;case 3:g=G2(P2[((s<<2)+n|0)-64>>2],P2[a+60>>2])+c|0;case 2:k=G2(P2[((s<<2)+n|0)-60>>2],P2[a+56>>2])+g|0;case 1:u=G2(P2[((s<<2)+n|0)-56>>2],P2[a+52>>2])+k|0;case 0:i=((((((((((((G2(P2[(i=(s<<2)+n|0)+-52>>2],P2[a+48>>2])+u|0)+G2(P2[i+-48>>2],P2[a+44>>2])|0)+G2(P2[i+-44>>2],P2[a+40>>2])|0)+G2(P2[i+-40>>2],P2[a+36>>2])|0)+G2(P2[i+-36>>2],P2[a+32>>2])|0)+G2(P2[i+-32>>2],P2[a+28>>2])|0)+G2(P2[i+-28>>2],P2[a+24>>2])|0)+G2(P2[i+-24>>2],P2[a+20>>2])|0)+G2(P2[i+-20>>2],P2[a+16>>2])|0)+G2(P2[i+-16>>2],P2[a+12>>2])|0)+G2(P2[i+-12>>2],P2[a+8>>2])|0)+G2(P2[i+-8>>2],P2[a+4>>2])|0)+G2(P2[i+-4>>2],P2[a>>2])|0;break;default:break e}if(P2[(u=s<<2)+n>>2]=P2[e+u>>2]+(i>>t),(0|(s=s+1|0))==(0|r))break}}else if(9<=i>>>0){if(11<=i>>>0){if(12!=(0|i)){if(!((0|r)<1))for(s=P2[n+-4>>2],i=P2[n+-8>>2],u=P2[n+-12>>2],k=P2[n+-16>>2],g=P2[n+-20>>2],c=P2[n+-24>>2],_=P2[n+-28>>2],b=P2[n+-32>>2],d=P2[n+-36>>2],A=P2[n+-40>>2],l=P2[n+-44>>2],L=P2[a>>2],I=P2[a+4>>2],B=P2[a+8>>2],D=P2[a+12>>2],E=P2[a+16>>2],F=P2[a+20>>2],y=P2[a+24>>2],C=P2[a+28>>2],h=P2[a+32>>2],v=P2[a+36>>2],w=P2[a+40>>2],a=0;;)if(l=(l=G2(p=A,v)+G2(l,w)|0)+G2(h,A=d)|0,l=(l=G2(d=b,C)+l|0)+G2(y,b=_)|0,l=(l=G2(_=c,F)+l|0)+G2(E,c=g)|0,l=G2(g=k,D)+l|0,m=G2(k=u,B)+l|0,l=a<<2,m=G2(u=i,I)+m|0,i=s,s=P2[l+e>>2]+(m+G2(L,i)>>t)|0,P2[n+l>>2]=s,l=p,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(s=P2[n+-4>>2],i=P2[n+-8>>2],u=P2[n+-12>>2],k=P2[n+-16>>2],g=P2[n+-20>>2],c=P2[n+-24>>2],_=P2[n+-28>>2],b=P2[n+-32>>2],d=P2[n+-36>>2],A=P2[n+-40>>2],l=P2[n+-44>>2],m=P2[n+-48>>2],f=P2[a>>2],o=P2[a+4>>2],L=P2[a+8>>2],I=P2[a+12>>2],B=P2[a+16>>2],D=P2[a+20>>2],E=P2[a+24>>2],F=P2[a+28>>2],y=P2[a+32>>2],C=P2[a+36>>2],h=P2[a+40>>2],v=P2[a+44>>2],a=0;;)if(m=G2(p=l,h)+G2(m,v)|0,m=(m=G2(l=A,C)+m|0)+G2(y,A=d)|0,m=(m=G2(d=b,F)+m|0)+G2(E,b=_)|0,m=(m=G2(_=c,D)+m|0)+G2(B,c=g)|0,m=G2(g=k,I)+m|0,w=G2(k=u,L)+m|0,m=a<<2,w=G2(u=i,o)+w|0,i=s,s=P2[m+e>>2]+(w+G2(f,i)>>t)|0,P2[n+m>>2]=s,m=p,(0|(a=a+1|0))==(0|r))break}else if(10!=(0|i)){if(!((0|r)<1))for(s=P2[n+-4>>2],i=P2[n+-8>>2],u=P2[n+-12>>2],k=P2[n+-16>>2],g=P2[n+-20>>2],c=P2[n+-24>>2],_=P2[n+-28>>2],b=P2[n+-32>>2],d=P2[n+-36>>2],E=P2[a>>2],F=P2[a+4>>2],y=P2[a+8>>2],C=P2[a+12>>2],h=P2[a+16>>2],v=P2[a+20>>2],w=P2[a+24>>2],m=P2[a+28>>2],p=P2[a+32>>2],a=0;;)if(d=(d=G2(A=b,m)+G2(d,p)|0)+G2(w,b=_)|0,d=(d=G2(_=c,v)+d|0)+G2(h,c=g)|0,d=G2(g=k,C)+d|0,l=G2(k=u,y)+d|0,d=a<<2,l=G2(u=i,F)+l|0,i=s,s=P2[d+e>>2]+(l+G2(E,i)>>t)|0,P2[n+d>>2]=s,d=A,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(s=P2[n+-4>>2],i=P2[n+-8>>2],u=P2[n+-12>>2],k=P2[n+-16>>2],g=P2[n+-20>>2],c=P2[n+-24>>2],_=P2[n+-28>>2],b=P2[n+-32>>2],d=P2[n+-36>>2],A=P2[n+-40>>2],B=P2[a>>2],D=P2[a+4>>2],E=P2[a+8>>2],F=P2[a+12>>2],y=P2[a+16>>2],C=P2[a+20>>2],h=P2[a+24>>2],v=P2[a+28>>2],w=P2[a+32>>2],m=P2[a+36>>2],a=0;;)if(A=G2(w,l=d)+G2(A,m)|0,A=(A=G2(d=b,v)+A|0)+G2(h,b=_)|0,A=(A=G2(_=c,C)+A|0)+G2(y,c=g)|0,A=G2(g=k,F)+A|0,p=G2(k=u,E)+A|0,A=a<<2,p=G2(u=i,D)+p|0,i=s,s=P2[A+e>>2]+(p+G2(B,i)>>t)|0,P2[n+A>>2]=s,A=l,(0|(a=a+1|0))==(0|r))break}else if(5<=i>>>0){if(7<=i>>>0){if(8!=(0|i)){if(!((0|r)<1))for(s=P2[n+-4>>2],i=P2[n+-8>>2],u=P2[n+-12>>2],k=P2[n+-16>>2],g=P2[n+-20>>2],c=P2[n+-24>>2],_=P2[n+-28>>2],h=P2[a>>2],v=P2[a+4>>2],w=P2[a+8>>2],m=P2[a+12>>2],p=P2[a+16>>2],l=P2[a+20>>2],A=P2[a+24>>2],a=0;;)if(_=(_=G2(b=c,l)+G2(A,_)|0)+G2(p,c=g)|0,_=G2(g=k,m)+_|0,d=G2(k=u,w)+_|0,_=a<<2,d=G2(u=i,v)+d|0,i=s,s=P2[_+e>>2]+(d+G2(h,i)>>t)|0,P2[n+_>>2]=s,_=b,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(s=P2[n+-4>>2],i=P2[n+-8>>2],u=P2[n+-12>>2],k=P2[n+-16>>2],g=P2[n+-20>>2],c=P2[n+-24>>2],_=P2[n+-28>>2],b=P2[n+-32>>2],y=P2[a>>2],C=P2[a+4>>2],h=P2[a+8>>2],v=P2[a+12>>2],w=P2[a+16>>2],m=P2[a+20>>2],p=P2[a+24>>2],l=P2[a+28>>2],a=0;;)if(b=G2(p,d=_)+G2(b,l)|0,b=(b=G2(_=c,m)+b|0)+G2(w,c=g)|0,b=G2(g=k,v)+b|0,A=G2(k=u,h)+b|0,b=a<<2,A=G2(u=i,C)+A|0,i=s,s=P2[b+e>>2]+(A+G2(y,i)>>t)|0,P2[n+b>>2]=s,b=d,(0|(a=a+1|0))==(0|r))break}else if(6!=(0|i)){if(!((0|r)<1))for(s=P2[n+-4>>2],i=P2[n+-8>>2],u=P2[n+-12>>2],k=P2[n+-16>>2],g=P2[n+-20>>2],p=P2[a>>2],l=P2[a+4>>2],A=P2[a+8>>2],d=P2[a+12>>2],b=P2[a+16>>2],a=0;;)if(g=G2(d,c=k)+G2(b,g)|0,_=G2(k=u,A)+g|0,g=a<<2,_=G2(u=i,l)+_|0,i=s,s=P2[g+e>>2]+(_+G2(p,i)>>t)|0,P2[n+g>>2]=s,g=c,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(s=P2[n+-4>>2],i=P2[n+-8>>2],u=P2[n+-12>>2],k=P2[n+-16>>2],g=P2[n+-20>>2],c=P2[n+-24>>2],w=P2[a>>2],m=P2[a+4>>2],p=P2[a+8>>2],l=P2[a+12>>2],A=P2[a+16>>2],d=P2[a+20>>2],a=0;;)if(c=G2(A,_=g)+G2(c,d)|0,c=G2(g=k,l)+c|0,b=G2(k=u,p)+c|0,c=a<<2,b=G2(u=i,m)+b|0,i=s,s=P2[c+e>>2]+(b+G2(w,i)>>t)|0,P2[n+c>>2]=s,c=_,(0|(a=a+1|0))==(0|r))break}else if(3<=i>>>0){if(4!=(0|i)){if(!((0|r)<1))for(s=P2[n+-4>>2],i=P2[n+-8>>2],u=P2[n+-12>>2],b=P2[a>>2],_=P2[a+4>>2],c=P2[a+8>>2],a=0;;)if(g=a<<2,u=G2(k=i,_)+G2(u,c)|0,i=s,s=P2[g+e>>2]+(u+G2(b,i)>>t)|0,P2[n+g>>2]=s,u=k,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(s=P2[n+-4>>2],i=P2[n+-8>>2],u=P2[n+-12>>2],k=P2[n+-16>>2],A=P2[a>>2],d=P2[a+4>>2],b=P2[a+8>>2],_=P2[a+12>>2],a=0;;)if(c=G2(g=u,b)+G2(k,_)|0,k=a<<2,c=G2(u=i,d)+c|0,i=s,s=P2[k+e>>2]+(c+G2(A,i)>>t)|0,P2[n+k>>2]=s,k=g,(0|(a=a+1|0))==(0|r))break}else if(2!=(0|i)){if(!((0|r)<1))for(s=P2[n+-4>>2],u=P2[a>>2],a=0;;)if(s=P2[(i=a<<2)+e>>2]+(G2(s,u)>>t)|0,P2[i+n>>2]=s,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(s=P2[n+-4>>2],i=P2[n+-8>>2],c=P2[a>>2],g=P2[a+4>>2],a=0;;)if(u=s,s=P2[(k=a<<2)+e>>2]+(G2(s,c)+G2(i,g)>>t)|0,P2[n+k>>2]=s,i=u,(0|(a=a+1|0))==(0|r))break},Q2[6]=function(e,r,a,i,t,n){e|=0,r|=0,a|=0,t|=0,n|=0;var N,G,f=0,o=0,s=0,c=0,u=0,b=0,A=0,k=0,l=0,_=0,d=0,m=0,g=0,p=0,w=0,h=0,v=0,y=0,C=0,E=0,F=0,B=0,D=0,L=0,I=0,M=0,Q=0,P=0,O=0,S=0,V=0,Y=0,R=0,T=0,U=0,x=0,z=0,j=0,H=0;if(13<=(i|=0)>>>0){if(!((0|r)<1))for(k=t,A=i+-13|0;;){e:switch((i=t=0)|A){case 19:t=b0(t=i=P2[((c<<2)+n|0)-128>>2],o=i>>31,i=P2[a+124>>2],i>>31),i=T2;case 18:o=b0(f=o=P2[((c<<2)+n|0)-124>>2],s=o>>31,o=P2[a+120>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 17:o=b0(f=o=P2[((c<<2)+n|0)-120>>2],s=o>>31,o=P2[a+116>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 16:o=b0(f=o=P2[((c<<2)+n|0)-116>>2],s=o>>31,o=P2[a+112>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 15:o=b0(f=o=P2[((c<<2)+n|0)-112>>2],s=o>>31,o=P2[a+108>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 14:o=b0(f=o=P2[((c<<2)+n|0)-108>>2],s=o>>31,o=P2[a+104>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 13:o=b0(f=o=P2[((c<<2)+n|0)-104>>2],s=o>>31,o=P2[a+100>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 12:o=b0(f=o=P2[((c<<2)+n|0)-100>>2],s=o>>31,o=P2[a+96>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 11:o=b0(f=o=P2[((c<<2)+n|0)-96>>2],s=o>>31,o=P2[a+92>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 10:o=b0(f=o=P2[((c<<2)+n|0)-92>>2],s=o>>31,o=P2[a+88>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 9:o=b0(f=o=P2[((c<<2)+n|0)-88>>2],s=o>>31,o=P2[a+84>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 8:o=b0(f=o=P2[((c<<2)+n|0)-84>>2],s=o>>31,o=P2[a+80>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 7:o=b0(f=o=P2[((c<<2)+n|0)-80>>2],s=o>>31,o=P2[a+76>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 6:o=b0(f=o=P2[((c<<2)+n|0)-76>>2],s=o>>31,o=P2[a+72>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 5:o=b0(f=o=P2[((c<<2)+n|0)-72>>2],s=o>>31,o=P2[a+68>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 4:o=b0(f=o=P2[((c<<2)+n|0)-68>>2],s=o>>31,o=P2[a+64>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 3:o=b0(f=o=P2[((c<<2)+n|0)-64>>2],s=o>>31,o=P2[a+60>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 2:o=b0(f=o=P2[((c<<2)+n|0)-60>>2],s=o>>31,o=P2[a+56>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 1:o=b0(f=o=P2[((c<<2)+n|0)-56>>2],s=o>>31,o=P2[a+52>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 0:s=b0(f=s=P2[(o=(c<<2)+n|0)+-52>>2],u=s>>31,s=P2[a+48>>2],s>>31)+t|0,f=i+T2|0,f=s>>>0>>0?f+1|0:f,t=b0(t=i=P2[o+-48>>2],u=i>>31,i=P2[a+44>>2],i>>31),f=T2+f|0,f=(i=t+s|0)>>>0>>0?f+1|0:f,s=i,t=b0(t=i=P2[o+-44>>2],u=i>>31,i=P2[a+40>>2],i>>31),f=T2+f|0,f=(i=s+t|0)>>>0>>0?f+1|0:f,s=i,t=b0(t=i=P2[o+-40>>2],u=i>>31,i=P2[a+36>>2],i>>31),f=T2+f|0,f=(i=s+t|0)>>>0>>0?f+1|0:f,s=i,t=b0(t=i=P2[o+-36>>2],u=i>>31,i=P2[a+32>>2],i>>31),f=T2+f|0,f=(i=s+t|0)>>>0>>0?f+1|0:f,s=i,t=b0(t=i=P2[o+-32>>2],u=i>>31,i=P2[a+28>>2],i>>31),f=T2+f|0,f=(i=s+t|0)>>>0>>0?f+1|0:f,s=i,t=b0(t=i=P2[o+-28>>2],u=i>>31,i=P2[a+24>>2],i>>31),f=T2+f|0,f=(i=s+t|0)>>>0>>0?f+1|0:f,s=i,t=b0(t=i=P2[o+-24>>2],u=i>>31,i=P2[a+20>>2],i>>31),f=T2+f|0,f=(i=s+t|0)>>>0>>0?f+1|0:f,s=i,t=b0(t=i=P2[o+-20>>2],u=i>>31,i=P2[a+16>>2],i>>31),f=T2+f|0,f=(i=s+t|0)>>>0>>0?f+1|0:f,s=i,t=b0(t=i=P2[o+-16>>2],u=i>>31,i=P2[a+12>>2],i>>31),f=T2+f|0,f=(i=s+t|0)>>>0>>0?f+1|0:f,s=i,t=b0(t=i=P2[o+-12>>2],u=i>>31,i=P2[a+8>>2],i>>31),f=T2+f|0,f=(i=s+t|0)>>>0>>0?f+1|0:f,s=i,t=b0(t=i=P2[o+-8>>2],u=i>>31,i=P2[a+4>>2],i>>31),f=T2+f|0,f=(i=s+t|0)>>>0>>0?f+1|0:f,s=i,t=b0(t=i=P2[o+-4>>2],o=i>>31,i=P2[a>>2],i>>31),f=T2+f|0,f=(i=s+t|0)>>>0>>0?f+1|0:f,t=i,i=f;break;default:break e}if(u=(o=c<<2)+n|0,f=P2[e+o>>2],s=t,o=31&(t=k),P2[u>>2]=f+(32<=(63&t)>>>0?i>>o:((1<>>o),(0|(c=c+1|0))==(0|r))break}}else if(9<=i>>>0){if(11<=i>>>0){if(12!=(0|i)){if(!((0|r)<1))for(c=P2[n+-4>>2],i=P2[n+-8>>2],k=P2[n+-12>>2],o=P2[n+-16>>2],s=P2[n+-20>>2],A=P2[n+-24>>2],u=P2[n+-28>>2],b=P2[n+-32>>2],l=P2[n+-36>>2],d=P2[n+-40>>2],_=P2[n+-44>>2],E=(m=f=P2[a>>2])>>31,B=(F=f=P2[a+4>>2])>>31,L=(C=f=P2[a+8>>2])>>31,v=(I=f=P2[a+12>>2])>>31,Q=(M=f=P2[a+16>>2])>>31,O=(D=f=P2[a+20>>2])>>31,h=(S=f=P2[a+24>>2])>>31,Y=(V=f=P2[a+28>>2])>>31,T=(P=f=P2[a+32>>2])>>31,w=(U=f=P2[a+36>>2])>>31,z=(x=a=P2[a+40>>2])>>31,a=0;;)if(R=(f=a<<2)+n|0,j=P2[e+f>>2],f=b0(g=d,d>>31,U,w),H=T2,d=l,_=(p=b0(_,_>>31,x,z))+f|0,f=T2+H|0,f=_>>>0

>>0?f+1|0:f,p=_,_=b0(l,l>>31,P,T),f=T2+f|0,f=(l=p+_|0)>>>0<_>>>0?f+1|0:f,p=_=l,_=b0(l=b,b>>31,V,Y),f=T2+f|0,f=(b=p+_|0)>>>0<_>>>0?f+1|0:f,_=b,b=u,u=_,_=b0(b,b>>31,S,h),f=T2+f|0,f=(u=u+_|0)>>>0<_>>>0?f+1|0:f,p=_=u,_=b0(u=A,A>>31,D,O),f=T2+f|0,f=(A=p+_|0)>>>0<_>>>0?f+1|0:f,p=_=A,_=b0(A=s,s>>31,M,Q),f=T2+f|0,f=(s=p+_|0)>>>0<_>>>0?f+1|0:f,p=_=s,_=b0(s=o,o>>31,I,v),f=T2+f|0,f=(o=p+_|0)>>>0<_>>>0?f+1|0:f,p=o,_=b0(o=k,o>>31,C,L),f=T2+f|0,f=(k=p+_|0)>>>0<_>>>0?f+1|0:f,y=R,p=_=k,_=b0(k=i,i>>31,F,B),f=T2+f|0,f=(i=p+_|0)>>>0<_>>>0?f+1|0:f,p=i,_=b0(i=c,i>>31,m,E),f=T2+f|0,f=(c=p+_|0)>>>0<_>>>0?f+1|0:f,R=c,_=31&(c=t),P2[y>>2]=c=(32<=(63&c)>>>0?f>>_:((1<<_)-1&f)<<32-_|R>>>_)+j|0,_=g,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(c=P2[n+-4>>2],i=P2[n+-8>>2],k=P2[n+-12>>2],o=P2[n+-16>>2],s=P2[n+-20>>2],A=P2[n+-24>>2],u=P2[n+-28>>2],b=P2[n+-32>>2],l=P2[n+-36>>2],d=P2[n+-40>>2],_=P2[n+-44>>2],f=P2[n+-48>>2],F=(E=g=P2[a>>2])>>31,C=(B=g=P2[a+4>>2])>>31,I=(L=g=P2[a+8>>2])>>31,M=(v=g=P2[a+12>>2])>>31,D=(Q=g=P2[a+16>>2])>>31,S=(O=g=P2[a+20>>2])>>31,V=(h=g=P2[a+24>>2])>>31,P=(Y=g=P2[a+28>>2])>>31,U=(T=g=P2[a+32>>2])>>31,x=(w=g=P2[a+36>>2])>>31,R=(z=g=P2[a+40>>2])>>31,H=(j=a=P2[a+44>>2])>>31,a=0;;)if(p=(g=a<<2)+n|0,G=P2[e+g>>2],m=b0(g=_,_>>31,z,R),y=T2,_=d,N=b0(f,f>>31,j,H),f=T2+y|0,f=(m=N+m|0)>>>0>>0?f+1|0:f,y=m,m=b0(d,d>>31,w,x),f=T2+f|0,f=(d=y+m|0)>>>0>>0?f+1|0:f,y=m=d,m=b0(d=l,l>>31,T,U),f=T2+f|0,f=(l=y+m|0)>>>0>>0?f+1|0:f,y=m=l,m=b0(l=b,b>>31,Y,P),f=T2+f|0,f=(b=y+m|0)>>>0>>0?f+1|0:f,m=b,b=u,u=m,m=b0(b,b>>31,h,V),f=T2+f|0,f=(u=u+m|0)>>>0>>0?f+1|0:f,y=m=u,m=b0(u=A,A>>31,O,S),f=T2+f|0,f=(A=y+m|0)>>>0>>0?f+1|0:f,y=m=A,m=b0(A=s,s>>31,Q,D),f=T2+f|0,f=(s=y+m|0)>>>0>>0?f+1|0:f,y=m=s,m=b0(s=o,o>>31,v,M),f=T2+f|0,f=(o=y+m|0)>>>0>>0?f+1|0:f,y=o,m=b0(o=k,o>>31,L,I),f=T2+f|0,f=(k=y+m|0)>>>0>>0?f+1|0:f,y=p,p=m=k,m=b0(k=i,i>>31,B,C),f=T2+f|0,f=(i=p+m|0)>>>0>>0?f+1|0:f,p=i,m=b0(i=c,i>>31,E,F),f=T2+f|0,f=(c=p+m|0)>>>0>>0?f+1|0:f,p=c,m=31&(c=t),P2[y>>2]=c=(32<=(63&c)>>>0?f>>m:((1<>>m)+G|0,f=g,(0|(a=a+1|0))==(0|r))break}else if(10!=(0|i)){if(!((0|r)<1))for(c=P2[n+-4>>2],i=P2[n+-8>>2],k=P2[n+-12>>2],o=P2[n+-16>>2],s=P2[n+-20>>2],A=P2[n+-24>>2],u=P2[n+-28>>2],b=P2[n+-32>>2],l=P2[n+-36>>2],g=(_=f=P2[a>>2])>>31,E=(m=f=P2[a+4>>2])>>31,B=(F=f=P2[a+8>>2])>>31,L=(C=f=P2[a+12>>2])>>31,v=(I=f=P2[a+16>>2])>>31,Q=(M=f=P2[a+20>>2])>>31,O=(D=f=P2[a+24>>2])>>31,h=(S=f=P2[a+28>>2])>>31,Y=(V=a=P2[a+32>>2])>>31,a=0;;)if(P=(f=a<<2)+n|0,T=P2[e+f>>2],f=b0(d=b,b>>31,S,h),U=T2,b=u,l=(w=b0(l,l>>31,V,Y))+f|0,f=T2+U|0,f=l>>>0>>0?f+1|0:f,u=l,l=b0(b,b>>31,D,O),f=T2+f|0,f=(u=u+l|0)>>>0>>0?f+1|0:f,w=l=u,l=b0(u=A,A>>31,M,Q),f=T2+f|0,f=(A=w+l|0)>>>0>>0?f+1|0:f,w=l=A,l=b0(A=s,s>>31,I,v),f=T2+f|0,f=(s=w+l|0)>>>0>>0?f+1|0:f,w=l=s,l=b0(s=o,o>>31,C,L),f=T2+f|0,f=(o=w+l|0)>>>0>>0?f+1|0:f,w=o,l=b0(o=k,o>>31,F,B),f=T2+f|0,f=(k=w+l|0)>>>0>>0?f+1|0:f,p=P,w=l=k,l=b0(k=i,i>>31,m,E),f=T2+f|0,f=(i=w+l|0)>>>0>>0?f+1|0:f,w=i,l=b0(i=c,i>>31,_,g),f=T2+f|0,f=(c=w+l|0)>>>0>>0?f+1|0:f,P=c,l=31&(c=t),P2[p>>2]=c=(32<=(63&c)>>>0?f>>l:((1<>>l)+T|0,l=d,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(c=P2[n+-4>>2],i=P2[n+-8>>2],k=P2[n+-12>>2],o=P2[n+-16>>2],s=P2[n+-20>>2],A=P2[n+-24>>2],u=P2[n+-28>>2],b=P2[n+-32>>2],l=P2[n+-36>>2],d=P2[n+-40>>2],m=(g=f=P2[a>>2])>>31,F=(E=f=P2[a+4>>2])>>31,C=(B=f=P2[a+8>>2])>>31,I=(L=f=P2[a+12>>2])>>31,M=(v=f=P2[a+16>>2])>>31,D=(Q=f=P2[a+20>>2])>>31,S=(O=f=P2[a+24>>2])>>31,V=(h=f=P2[a+28>>2])>>31,P=(Y=f=P2[a+32>>2])>>31,U=(T=a=P2[a+36>>2])>>31,a=0;;)if(w=(f=a<<2)+n|0,x=P2[e+f>>2],f=b0(_=l,l>>31,Y,P),z=T2,l=b,d=(R=b0(d,d>>31,T,U))+f|0,f=T2+z|0,f=d>>>0>>0?f+1|0:f,p=d,d=b0(b,b>>31,h,V),f=T2+f|0,f=(b=p+d|0)>>>0>>0?f+1|0:f,d=b,b=u,u=d,d=b0(b,b>>31,O,S),f=T2+f|0,f=(u=u+d|0)>>>0>>0?f+1|0:f,p=d=u,d=b0(u=A,A>>31,Q,D),f=T2+f|0,f=(A=p+d|0)>>>0>>0?f+1|0:f,p=d=A,d=b0(A=s,s>>31,v,M),f=T2+f|0,f=(s=p+d|0)>>>0>>0?f+1|0:f,p=d=s,d=b0(s=o,o>>31,L,I),f=T2+f|0,f=(o=p+d|0)>>>0>>0?f+1|0:f,p=o,d=b0(o=k,o>>31,B,C),f=T2+f|0,f=(k=p+d|0)>>>0>>0?f+1|0:f,p=w,w=d=k,d=b0(k=i,i>>31,E,F),f=T2+f|0,f=(i=w+d|0)>>>0>>0?f+1|0:f,w=i,d=b0(i=c,i>>31,g,m),f=T2+f|0,f=(c=w+d|0)>>>0>>0?f+1|0:f,w=c,d=31&(c=t),P2[p>>2]=c=(32<=(63&c)>>>0?f>>d:((1<>>d)+x|0,d=_,(0|(a=a+1|0))==(0|r))break}else if(5<=i>>>0){if(7<=i>>>0){if(8!=(0|i)){if(!((0|r)<1))for(c=P2[n+-4>>2],i=P2[n+-8>>2],k=P2[n+-12>>2],o=P2[n+-16>>2],s=P2[n+-20>>2],A=P2[n+-24>>2],u=P2[n+-28>>2],d=(l=b=P2[a>>2])>>31,g=(_=b=P2[a+4>>2])>>31,E=(m=b=P2[a+8>>2])>>31,B=(F=b=P2[a+12>>2])>>31,L=(C=b=P2[a+16>>2])>>31,v=(I=b=P2[a+20>>2])>>31,Q=(M=a=P2[a+24>>2])>>31,a=0;;)if(D=(b=a<<2)+n|0,O=P2[e+b>>2],f=b0(b=A,b>>31,I,v),S=T2,A=s,u=(h=b0(u,u>>31,M,Q))+f|0,f=T2+S|0,f=u>>>0>>0?f+1|0:f,h=u,u=b0(s,s>>31,C,L),f=T2+f|0,f=(s=h+u|0)>>>0>>0?f+1|0:f,h=u=s,u=b0(s=o,o>>31,F,B),f=T2+f|0,f=(o=h+u|0)>>>0>>0?f+1|0:f,h=o,u=b0(o=k,o>>31,m,E),f=T2+f|0,f=(k=h+u|0)>>>0>>0?f+1|0:f,w=D,h=u=k,u=b0(k=i,i>>31,_,g),f=T2+f|0,f=(i=h+u|0)>>>0>>0?f+1|0:f,h=i,u=b0(i=c,i>>31,l,d),f=T2+f|0,f=(c=h+u|0)>>>0>>0?f+1|0:f,D=c,u=31&(c=t),P2[w>>2]=c=(32<=(63&c)>>>0?f>>u:((1<>>u)+O|0,u=b,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(c=P2[n+-4>>2],i=P2[n+-8>>2],k=P2[n+-12>>2],o=P2[n+-16>>2],s=P2[n+-20>>2],A=P2[n+-24>>2],u=P2[n+-28>>2],b=P2[n+-32>>2],_=(d=f=P2[a>>2])>>31,m=(g=f=P2[a+4>>2])>>31,F=(E=f=P2[a+8>>2])>>31,C=(B=f=P2[a+12>>2])>>31,I=(L=f=P2[a+16>>2])>>31,M=(v=f=P2[a+20>>2])>>31,D=(Q=f=P2[a+24>>2])>>31,S=(O=a=P2[a+28>>2])>>31,a=0;;)if(h=(f=a<<2)+n|0,V=P2[e+f>>2],f=b0(l=u,u>>31,Q,D),Y=T2,u=A,b=(P=b0(b,b>>31,O,S))+f|0,f=T2+Y|0,f=b>>>0

>>0?f+1|0:f,w=b,b=b0(A,A>>31,v,M),f=T2+f|0,f=(A=w+b|0)>>>0>>0?f+1|0:f,w=b=A,b=b0(A=s,s>>31,L,I),f=T2+f|0,f=(s=w+b|0)>>>0>>0?f+1|0:f,w=b=s,b=b0(s=o,o>>31,B,C),f=T2+f|0,f=(o=w+b|0)>>>0>>0?f+1|0:f,w=o,b=b0(o=k,o>>31,E,F),f=T2+f|0,f=(k=w+b|0)>>>0>>0?f+1|0:f,w=h,h=b=k,b=b0(k=i,i>>31,g,m),f=T2+f|0,f=(i=h+b|0)>>>0>>0?f+1|0:f,h=i,b=b0(i=c,i>>31,d,_),f=T2+f|0,f=(c=h+b|0)>>>0>>0?f+1|0:f,h=c,b=31&(c=t),P2[w>>2]=c=(32<=(63&c)>>>0?f>>b:((1<>>b)+V|0,b=l,(0|(a=a+1|0))==(0|r))break}else if(6!=(0|i)){if(!((0|r)<1))for(c=P2[n+-4>>2],i=P2[n+-8>>2],k=P2[n+-12>>2],o=P2[n+-16>>2],s=P2[n+-20>>2],b=(u=A=P2[a>>2])>>31,d=(l=A=P2[a+4>>2])>>31,g=(_=A=P2[a+8>>2])>>31,E=(m=A=P2[a+12>>2])>>31,B=(F=a=P2[a+16>>2])>>31,a=0;;)if(C=(A=a<<2)+n|0,L=P2[e+A>>2],f=b0(A=o,o>>31,m,E),I=T2,o=k,s=(v=b0(s,s>>31,F,B))+f|0,f=T2+I|0,f=s>>>0>>0?f+1|0:f,k=s,s=b0(o,o>>31,_,g),f=T2+f|0,f=(k=k+s|0)>>>0>>0?f+1|0:f,v=s=k,s=b0(k=i,i>>31,l,d),f=T2+f|0,f=(i=v+s|0)>>>0>>0?f+1|0:f,s=i,c=b0(i=c,i>>31,u,b),f=T2+f|0,f=(s=s+c|0)>>>0>>0?f+1|0:f,c=31&t,P2[C>>2]=c=(32<=(63&t)>>>0?f>>c:((1<>>c)+L|0,s=A,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(c=P2[n+-4>>2],i=P2[n+-8>>2],k=P2[n+-12>>2],o=P2[n+-16>>2],s=P2[n+-20>>2],A=P2[n+-24>>2],l=(b=u=P2[a>>2])>>31,_=(d=u=P2[a+4>>2])>>31,m=(g=u=P2[a+8>>2])>>31,F=(E=u=P2[a+12>>2])>>31,C=(B=u=P2[a+16>>2])>>31,I=(L=a=P2[a+20>>2])>>31,a=0;;)if(v=(u=a<<2)+n|0,M=P2[e+u>>2],f=b0(u=s,s>>31,B,C),Q=T2,s=o,A=(D=b0(A,A>>31,L,I))+f|0,f=T2+Q|0,f=A>>>0>>0?f+1|0:f,h=A,A=b0(o,o>>31,E,F),f=T2+f|0,f=(o=h+A|0)>>>0>>0?f+1|0:f,h=o,A=b0(o=k,o>>31,g,m),f=T2+f|0,f=(k=h+A|0)>>>0>>0?f+1|0:f,h=v,v=A=k,A=b0(k=i,i>>31,d,_),f=T2+f|0,f=(i=v+A|0)>>>0>>0?f+1|0:f,A=i,c=b0(i=c,i>>31,b,l),f=T2+f|0,f=(A=A+c|0)>>>0>>0?f+1|0:f,c=31&t,P2[h>>2]=c=(32<=(63&t)>>>0?f>>c:((1<>>c)+M|0,A=u,(0|(a=a+1|0))==(0|r))break}else if(3<=i>>>0){if(4!=(0|i)){if(!((0|r)<1))for(c=P2[n+-4>>2],i=P2[n+-8>>2],k=P2[n+-12>>2],u=(A=o=P2[a>>2])>>31,l=(b=o=P2[a+4>>2])>>31,_=(d=a=P2[a+8>>2])>>31,a=0;;)if(s=(o=a<<2)+n|0,g=P2[e+o>>2],i=b0(o=i,o>>31,b,l),f=T2,m=s,k=b0(k,k>>31,d,_),f=T2+f|0,f=(i=k+i|0)>>>0>>0?f+1|0:f,s=i,c=b0(i=c,i>>31,A,u),f=T2+f|0,f=(k=s+c|0)>>>0>>0?f+1|0:f,c=k,s=31&t,P2[m>>2]=c=(32<=(63&t)>>>0?f>>s:((1<>>s)+g|0,k=o,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(c=P2[n+-4>>2],i=P2[n+-8>>2],k=P2[n+-12>>2],o=P2[n+-16>>2],b=(u=s=P2[a>>2])>>31,d=(l=s=P2[a+4>>2])>>31,g=(_=s=P2[a+8>>2])>>31,E=(m=a=P2[a+12>>2])>>31,a=0;;)if(A=(s=a<<2)+n|0,F=P2[e+s>>2],f=b0(s=k,s>>31,_,g),B=T2,k=i,v=A,o=(C=b0(o,o>>31,m,E))+f|0,f=T2+B|0,f=o>>>0>>0?f+1|0:f,A=o,o=b0(i,i>>31,l,d),f=T2+f|0,f=(i=A+o|0)>>>0>>0?f+1|0:f,o=i,c=b0(i=c,i>>31,u,b),f=T2+f|0,f=(o=o+c|0)>>>0>>0?f+1|0:f,c=o,A=31&(o=t),P2[v>>2]=c=(32<=(63&o)>>>0?f>>A:((1<>>A)+F|0,o=s,(0|(a=a+1|0))==(0|r))break}else if(2!=(0|i)){if(!((0|r)<1))for(c=P2[n+-4>>2],A=(s=a=P2[a>>2])>>31,a=0;;)if(u=(i=a<<2)+n|0,f=P2[e+i>>2],c=b0(c,c>>31,s,A),o=T2,k=31&(i=t),P2[u>>2]=c=f+(32<=(63&i)>>>0?o>>k:((1<>>k)|0,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(c=P2[n+-4>>2],i=P2[n+-8>>2],A=(s=k=P2[a>>2])>>31,b=(u=a=P2[a+4>>2])>>31,a=0;;)if(o=(k=a<<2)+n|0,l=P2[e+k>>2],c=b0(k=c,c>>31,s,A),f=T2,_=o,o=c,c=b0(i,i>>31,u,b),f=T2+f|0,f=(i=o+c|0)>>>0>>0?f+1|0:f,c=i,o=31&(i=t),P2[_>>2]=c=(32<=(63&i)>>>0?f>>o:((1<>>o)+l|0,i=k,(0|(a=a+1|0))==(0|r))break},Q2[7]=function(e,r,a){e|=0,r|=0;var i=0,t=0,i=P2[(a|=0)+4>>2];if(!P2[i>>2]&&(t=P2[i+20>>2])&&Q2[t](a,P2[i+48>>2]))return P2[r>>2]=0,P2[P2[a>>2]>>2]=4,0;e:{r:if(P2[r>>2])if(i=P2[a+4>>2],!P2[i+3632>>2]|S2[i+6152>>2]<21){a:{i:{t:{n:{if(P2[i>>2])switch((t=0)|B0(P2[a>>2]+32|0,e,r,a,P2[i+48>>2])){case 0:case 2:break i;case 1:break t;default:break n}if(2!=(0|(t=0|Q2[P2[i+4>>2]](a,e,r,P2[i+48>>2]))))break i}P2[P2[a>>2]>>2]=7;break r}if(e=1,P2[r>>2])break e;break a}if(e=1,P2[r>>2])break e;if(1!=(0|t)){if(r=P2[a+4>>2],P2[r>>2])break e;if(!(i=P2[r+20>>2]))break e;if(!Q2[i](a,P2[r+48>>2]))break e}}P2[P2[a>>2]>>2]=4}else P2[P2[a>>2]>>2]=7;else P2[P2[a>>2]>>2]=7;e=0}return 0|e},Q2[8]=function(e,r,a,i){return(e=0|Q2[P2[P2[(e|=0)+4>>2]+4>>2]](e,r|=0,a|=0,i|=0))>>>0<=2?P2[7572+(e<<2)>>2]:5},Q2[9]=function(e){return 0},Q2[10]=function(e,r,a){r|=0,a|=0;var i,t,n,f,o,s=0,c=0;R2=o=R2-32|0,s=P2[(e|=0)+28>>2],P2[16+o>>2]=s,i=P2[e+20>>2],P2[28+o>>2]=a,P2[24+o>>2]=r,s=(P2[20+o>>2]=r=i-s|0)+a|0;e:{r:{a:{if(!M0(0|D(P2[e+60>>(c=2)],r=16+o|0,2,12+o|0)))for(;;){if((0|(i=P2[12+o>>2]))==(0|s))break a;if((0|i)<=-1)break r;if(t=P2[r+4>>2],P2[(f=((n=t>>>0>>0)<<3)+r|0)>>2]=(t=i-(n?t:0)|0)+P2[f>>2],P2[(f=(n?12:4)+r|0)>>2]=P2[f>>2]-t,s=s-i|0,M0(0|D(P2[e+60>>2],0|(r=n?r+8|0:r),0|(c=c-n|0),12+o|0)))break}if((P2[12+o>>2]=-1)!=(0|s))break r}r=P2[e+44>>2],P2[e+28>>2]=r,P2[e+20>>2]=r,P2[e+16>>2]=r+P2[e+48>>2],e=a;break e}P2[e+28>>2]=0,P2[e+16>>2]=0,P2[e+20>>2]=0,P2[e>>2]=32|P2[e>>2],2!=((e=0)|c)&&(e=a-P2[r+4>>2]|0)}return R2=32+o|0,0|e},Q2[11]=function(e,r,a,i){return T2=0},Q2[12]=function(e,r,a,i,t,n){e|=0,r|=0,a|=0,t|=0,n|=0;var f,o,s=0,c=0,u=0,b=0,A=0,k=0,l=0,_=0,d=0,m=0,g=0,p=0,w=0,h=0,v=0,y=0,C=0,E=0,F=0,B=0,D=0,L=0,I=0;if(13<=(i|=0)>>>0){if(!((0|r)<1))for(B=i+-13|0;;){e:switch((i=c=u=b=A=k=l=_=d=m=g=w=D=E=F=y=C=h=v=p=0)|B){case 19:p=G2(P2[((s<<2)+e|0)-128>>2],P2[a+124>>2]);case 18:v=G2(P2[((s<<2)+e|0)-124>>2],P2[a+120>>2])+p|0;case 17:h=G2(P2[((s<<2)+e|0)-120>>2],P2[a+116>>2])+v|0;case 16:C=G2(P2[((s<<2)+e|0)-116>>2],P2[a+112>>2])+h|0;case 15:y=G2(P2[((s<<2)+e|0)-112>>2],P2[a+108>>2])+C|0;case 14:F=G2(P2[((s<<2)+e|0)-108>>2],P2[a+104>>2])+y|0;case 13:E=G2(P2[((s<<2)+e|0)-104>>2],P2[a+100>>2])+F|0;case 12:D=G2(P2[((s<<2)+e|0)-100>>2],P2[a+96>>2])+E|0;case 11:w=G2(P2[((s<<2)+e|0)-96>>2],P2[a+92>>2])+D|0;case 10:g=G2(P2[((s<<2)+e|0)-92>>2],P2[a+88>>2])+w|0;case 9:m=G2(P2[((s<<2)+e|0)-88>>2],P2[a+84>>2])+g|0;case 8:d=G2(P2[((s<<2)+e|0)-84>>2],P2[a+80>>2])+m|0;case 7:_=G2(P2[((s<<2)+e|0)-80>>2],P2[a+76>>2])+d|0;case 6:l=G2(P2[((s<<2)+e|0)-76>>2],P2[a+72>>2])+_|0;case 5:k=G2(P2[((s<<2)+e|0)-72>>2],P2[a+68>>2])+l|0;case 4:A=G2(P2[((s<<2)+e|0)-68>>2],P2[a+64>>2])+k|0;case 3:b=G2(P2[((s<<2)+e|0)-64>>2],P2[a+60>>2])+A|0;case 2:u=G2(P2[((s<<2)+e|0)-60>>2],P2[a+56>>2])+b|0;case 1:c=G2(P2[((s<<2)+e|0)-56>>2],P2[a+52>>2])+u|0;case 0:i=((((((((((((G2(P2[(i=(s<<2)+e|0)+-52>>2],P2[a+48>>2])+c|0)+G2(P2[i+-48>>2],P2[a+44>>2])|0)+G2(P2[i+-44>>2],P2[a+40>>2])|0)+G2(P2[i+-40>>2],P2[a+36>>2])|0)+G2(P2[i+-36>>2],P2[a+32>>2])|0)+G2(P2[i+-32>>2],P2[a+28>>2])|0)+G2(P2[i+-28>>2],P2[a+24>>2])|0)+G2(P2[i+-24>>2],P2[a+20>>2])|0)+G2(P2[i+-20>>2],P2[a+16>>2])|0)+G2(P2[i+-16>>2],P2[a+12>>2])|0)+G2(P2[i+-12>>2],P2[a+8>>2])|0)+G2(P2[i+-8>>2],P2[a+4>>2])|0)+G2(P2[i+-4>>2],P2[a>>2])|0;break;default:break e}if(P2[(c=s<<2)+n>>2]=P2[e+c>>2]-(i>>t),(0|(s=s+1|0))==(0|r))break}}else if(9<=i>>>0){if(11<=i>>>0){if(12!=(0|i)){if(!((0|r)<1))for(m=P2[e+-4>>2],s=P2[e+-8>>2],i=P2[e+-12>>2],c=P2[e+-16>>2],u=P2[e+-20>>2],b=P2[e+-24>>2],A=P2[e+-28>>2],k=P2[e+-32>>2],l=P2[e+-36>>2],_=P2[e+-40>>2],g=P2[e+-44>>2],w=P2[a>>2],p=P2[a+4>>2],v=P2[a+8>>2],h=P2[a+12>>2],C=P2[a+16>>2],y=P2[a+20>>2],F=P2[a+24>>2],E=P2[a+28>>2],D=P2[a+32>>2],B=P2[a+36>>2],I=P2[a+40>>2],a=0;;)if(d=_,_=l,l=k,k=A,A=b,b=u,u=c,c=i,i=s,s=m,m=P2[(L=a<<2)+e>>2],P2[n+L>>2]=m-((((((((((G2(d,B)+G2(g,I)|0)+G2(_,D)|0)+G2(l,E)|0)+G2(k,F)|0)+G2(A,y)|0)+G2(b,C)|0)+G2(u,h)|0)+G2(c,v)|0)+G2(i,p)|0)+G2(s,w)>>t),g=d,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(g=P2[e+-4>>2],s=P2[e+-8>>2],i=P2[e+-12>>2],c=P2[e+-16>>2],u=P2[e+-20>>2],b=P2[e+-24>>2],A=P2[e+-28>>2],k=P2[e+-32>>2],l=P2[e+-36>>2],_=P2[e+-40>>2],d=P2[e+-44>>2],w=P2[e+-48>>2],p=P2[a>>2],v=P2[a+4>>2],h=P2[a+8>>2],C=P2[a+12>>2],y=P2[a+16>>2],F=P2[a+20>>2],E=P2[a+24>>2],D=P2[a+28>>2],B=P2[a+32>>2],I=P2[a+36>>2],L=P2[a+40>>2],o=P2[a+44>>2],a=0;;)if(m=d,d=_,_=l,l=k,k=A,A=b,b=u,u=c,c=i,i=s,s=g,g=P2[(f=a<<2)+e>>2],P2[n+f>>2]=g-(((((((((((G2(m,L)+G2(w,o)|0)+G2(d,I)|0)+G2(_,B)|0)+G2(l,D)|0)+G2(k,E)|0)+G2(A,F)|0)+G2(b,y)|0)+G2(u,C)|0)+G2(c,h)|0)+G2(i,v)|0)+G2(s,p)>>t),w=m,(0|(a=a+1|0))==(0|r))break}else if(10!=(0|i)){if(!((0|r)<1))for(_=P2[e+-4>>2],s=P2[e+-8>>2],i=P2[e+-12>>2],c=P2[e+-16>>2],u=P2[e+-20>>2],b=P2[e+-24>>2],A=P2[e+-28>>2],k=P2[e+-32>>2],d=P2[e+-36>>2],g=P2[a>>2],m=P2[a+4>>2],w=P2[a+8>>2],p=P2[a+12>>2],v=P2[a+16>>2],h=P2[a+20>>2],C=P2[a+24>>2],y=P2[a+28>>2],F=P2[a+32>>2],a=0;;)if(l=k,k=A,A=b,b=u,u=c,c=i,i=s,s=_,_=P2[(E=a<<2)+e>>2],P2[n+E>>2]=_-((((((((G2(l,y)+G2(d,F)|0)+G2(k,C)|0)+G2(A,h)|0)+G2(b,v)|0)+G2(u,p)|0)+G2(c,w)|0)+G2(i,m)|0)+G2(s,g)>>t),d=l,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(d=P2[e+-4>>2],s=P2[e+-8>>2],i=P2[e+-12>>2],c=P2[e+-16>>2],u=P2[e+-20>>2],b=P2[e+-24>>2],A=P2[e+-28>>2],k=P2[e+-32>>2],l=P2[e+-36>>2],m=P2[e+-40>>2],g=P2[a>>2],w=P2[a+4>>2],p=P2[a+8>>2],v=P2[a+12>>2],h=P2[a+16>>2],C=P2[a+20>>2],y=P2[a+24>>2],F=P2[a+28>>2],E=P2[a+32>>2],D=P2[a+36>>2],a=0;;)if(_=l,l=k,k=A,A=b,b=u,u=c,c=i,i=s,s=d,d=P2[(B=a<<2)+e>>2],P2[n+B>>2]=d-(((((((((G2(_,E)+G2(m,D)|0)+G2(l,F)|0)+G2(k,y)|0)+G2(A,C)|0)+G2(b,h)|0)+G2(u,v)|0)+G2(c,p)|0)+G2(i,w)|0)+G2(s,g)>>t),m=_,(0|(a=a+1|0))==(0|r))break}else if(5<=i>>>0){if(7<=i>>>0){if(8!=(0|i)){if(!((0|r)<1))for(k=P2[e+-4>>2],s=P2[e+-8>>2],i=P2[e+-12>>2],c=P2[e+-16>>2],u=P2[e+-20>>2],b=P2[e+-24>>2],l=P2[e+-28>>2],_=P2[a>>2],d=P2[a+4>>2],g=P2[a+8>>2],m=P2[a+12>>2],w=P2[a+16>>2],p=P2[a+20>>2],v=P2[a+24>>2],a=0;;)if(A=b,b=u,u=c,c=i,i=s,s=k,k=P2[(h=a<<2)+e>>2],P2[n+h>>2]=k-((((((G2(A,p)+G2(l,v)|0)+G2(b,w)|0)+G2(u,m)|0)+G2(c,g)|0)+G2(i,d)|0)+G2(s,_)>>t),l=A,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(l=P2[e+-4>>2],s=P2[e+-8>>2],i=P2[e+-12>>2],c=P2[e+-16>>2],u=P2[e+-20>>2],b=P2[e+-24>>2],A=P2[e+-28>>2],_=P2[e+-32>>2],d=P2[a>>2],g=P2[a+4>>2],m=P2[a+8>>2],w=P2[a+12>>2],p=P2[a+16>>2],v=P2[a+20>>2],h=P2[a+24>>2],C=P2[a+28>>2],a=0;;)if(k=A,A=b,b=u,u=c,c=i,i=s,s=l,l=P2[(y=a<<2)+e>>2],P2[n+y>>2]=l-(((((((G2(k,h)+G2(_,C)|0)+G2(A,v)|0)+G2(b,p)|0)+G2(u,w)|0)+G2(c,m)|0)+G2(i,g)|0)+G2(s,d)>>t),_=k,(0|(a=a+1|0))==(0|r))break}else if(6!=(0|i)){if(!((0|r)<1))for(b=P2[e+-4>>2],s=P2[e+-8>>2],i=P2[e+-12>>2],c=P2[e+-16>>2],A=P2[e+-20>>2],k=P2[a>>2],l=P2[a+4>>2],_=P2[a+8>>2],d=P2[a+12>>2],g=P2[a+16>>2],a=0;;)if(u=c,c=i,i=s,s=b,b=P2[(m=a<<2)+e>>2],P2[n+m>>2]=b-((((G2(u,d)+G2(A,g)|0)+G2(c,_)|0)+G2(i,l)|0)+G2(s,k)>>t),A=u,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(A=P2[e+-4>>2],s=P2[e+-8>>2],i=P2[e+-12>>2],c=P2[e+-16>>2],u=P2[e+-20>>2],k=P2[e+-24>>2],l=P2[a>>2],_=P2[a+4>>2],d=P2[a+8>>2],g=P2[a+12>>2],m=P2[a+16>>2],w=P2[a+20>>2],a=0;;)if(b=u,u=c,c=i,i=s,s=A,A=P2[(p=a<<2)+e>>2],P2[n+p>>2]=A-(((((G2(b,m)+G2(k,w)|0)+G2(u,g)|0)+G2(c,d)|0)+G2(i,_)|0)+G2(s,l)>>t),k=b,(0|(a=a+1|0))==(0|r))break}else if(3<=i>>>0){if(4!=(0|i)){if(!((0|r)<1))for(c=P2[e+-4>>2],s=P2[e+-8>>2],u=P2[e+-12>>2],b=P2[a>>2],A=P2[a+4>>2],k=P2[a+8>>2],a=0;;)if(i=s,s=c,c=P2[(l=a<<2)+e>>2],P2[n+l>>2]=c-((G2(i,A)+G2(u,k)|0)+G2(s,b)>>t),u=i,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(u=P2[e+-4>>2],s=P2[e+-8>>2],i=P2[e+-12>>2],b=P2[e+-16>>2],A=P2[a>>2],k=P2[a+4>>2],l=P2[a+8>>2],_=P2[a+12>>2],a=0;;)if(c=i,i=s,s=u,u=P2[(d=a<<2)+e>>2],P2[n+d>>2]=u-(((G2(c,l)+G2(b,_)|0)+G2(i,k)|0)+G2(s,A)>>t),b=c,(0|(a=a+1|0))==(0|r))break}else if(2!=(0|i)){if(!((0|r)<1))for(s=P2[e+-4>>2],i=P2[a>>2],a=0;;)if(c=G2(i,s),s=P2[(u=a<<2)+e>>2],P2[n+u>>2]=s-(c>>t),(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(i=P2[e+-4>>2],c=P2[e+-8>>2],u=P2[a>>2],b=P2[a+4>>2],a=0;;)if(s=i,i=P2[(A=a<<2)+e>>2],P2[n+A>>2]=i-(G2(s,u)+G2(c,b)>>t),c=s,(0|(a=a+1|0))==(0|r))break},Q2[13]=function(e,r,a,i,t,n){e|=0,r|=0,a|=0,t|=0,n|=0;var N,f=0,o=0,s=0,c=0,u=0,b=0,A=0,k=0,l=0,_=0,d=0,m=0,g=0,p=0,w=0,h=0,v=0,y=0,C=0,E=0,F=0,B=0,D=0,L=0,I=0,M=0,Q=0,P=0,O=0,S=0,G=0,V=0,Y=0,R=0,T=0,U=0,x=0,z=0,j=0;if(13<=(i|=0)>>>0){if(!((0|r)<1))for(g=t,A=i+-13|0;;){e:switch((i=t=0)|A){case 19:t=b0(t=i=P2[((_<<2)+e|0)-128>>2],o=i>>31,i=P2[a+124>>2],i>>31),i=T2;case 18:o=b0(f=o=P2[((_<<2)+e|0)-124>>2],s=o>>31,o=P2[a+120>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 17:o=b0(f=o=P2[((_<<2)+e|0)-120>>2],s=o>>31,o=P2[a+116>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 16:o=b0(f=o=P2[((_<<2)+e|0)-116>>2],s=o>>31,o=P2[a+112>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 15:o=b0(f=o=P2[((_<<2)+e|0)-112>>2],s=o>>31,o=P2[a+108>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 14:o=b0(f=o=P2[((_<<2)+e|0)-108>>2],s=o>>31,o=P2[a+104>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 13:o=b0(f=o=P2[((_<<2)+e|0)-104>>2],s=o>>31,o=P2[a+100>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 12:o=b0(f=o=P2[((_<<2)+e|0)-100>>2],s=o>>31,o=P2[a+96>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 11:o=b0(f=o=P2[((_<<2)+e|0)-96>>2],s=o>>31,o=P2[a+92>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 10:o=b0(f=o=P2[((_<<2)+e|0)-92>>2],s=o>>31,o=P2[a+88>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 9:o=b0(f=o=P2[((_<<2)+e|0)-88>>2],s=o>>31,o=P2[a+84>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 8:o=b0(f=o=P2[((_<<2)+e|0)-84>>2],s=o>>31,o=P2[a+80>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 7:o=b0(f=o=P2[((_<<2)+e|0)-80>>2],s=o>>31,o=P2[a+76>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 6:o=b0(f=o=P2[((_<<2)+e|0)-76>>2],s=o>>31,o=P2[a+72>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 5:o=b0(f=o=P2[((_<<2)+e|0)-72>>2],s=o>>31,o=P2[a+68>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 4:o=b0(f=o=P2[((_<<2)+e|0)-68>>2],s=o>>31,o=P2[a+64>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 3:o=b0(f=o=P2[((_<<2)+e|0)-64>>2],s=o>>31,o=P2[a+60>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 2:o=b0(f=o=P2[((_<<2)+e|0)-60>>2],s=o>>31,o=P2[a+56>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 1:o=b0(f=o=P2[((_<<2)+e|0)-56>>2],s=o>>31,o=P2[a+52>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,t=o,i=f;case 0:o=b0(f=o=P2[(s=(_<<2)+e|0)+-52>>2],c=o>>31,o=P2[a+48>>2],o>>31)+t|0,f=i+T2|0,f=o>>>0>>0?f+1|0:f,i=b0(t=i=P2[s+-48>>2],c=i>>31,i=P2[a+44>>2],i>>31),f=T2+f|0,f=(t=i+o|0)>>>0>>0?f+1|0:f,i=b0(o=i=P2[s+-44>>2],c=i>>31,i=P2[a+40>>2],i>>31),f=T2+f|0,f=(t=i+t|0)>>>0>>0?f+1|0:f,i=b0(o=i=P2[s+-40>>2],c=i>>31,i=P2[a+36>>2],i>>31),f=T2+f|0,f=(t=i+t|0)>>>0>>0?f+1|0:f,i=b0(o=i=P2[s+-36>>2],c=i>>31,i=P2[a+32>>2],i>>31),f=T2+f|0,f=(t=i+t|0)>>>0>>0?f+1|0:f,i=b0(o=i=P2[s+-32>>2],c=i>>31,i=P2[a+28>>2],i>>31),f=T2+f|0,f=(t=i+t|0)>>>0>>0?f+1|0:f,i=b0(o=i=P2[s+-28>>2],c=i>>31,i=P2[a+24>>2],i>>31),f=T2+f|0,f=(t=i+t|0)>>>0>>0?f+1|0:f,i=b0(o=i=P2[s+-24>>2],c=i>>31,i=P2[a+20>>2],i>>31),f=T2+f|0,f=(t=i+t|0)>>>0>>0?f+1|0:f,i=b0(o=i=P2[s+-20>>2],c=i>>31,i=P2[a+16>>2],i>>31),f=T2+f|0,f=(t=i+t|0)>>>0>>0?f+1|0:f,i=b0(o=i=P2[s+-16>>2],c=i>>31,i=P2[a+12>>2],i>>31),f=T2+f|0,f=(t=i+t|0)>>>0>>0?f+1|0:f,i=b0(o=i=P2[s+-12>>2],c=i>>31,i=P2[a+8>>2],i>>31),f=T2+f|0,f=(t=i+t|0)>>>0>>0?f+1|0:f,i=b0(o=i=P2[s+-8>>2],c=i>>31,i=P2[a+4>>2],i>>31),f=T2+f|0,f=(t=i+t|0)>>>0>>0?f+1|0:f,i=b0(o=i=P2[s+-4>>2],s=i>>31,i=P2[a>>2],i>>31),f=T2+f|0,i=f=(t=i+t|0)>>>0>>0?f+1|0:f;break;default:break e}if(f=(o=_<<2)+n|0,c=P2[e+o>>2],o=i,s=31&(i=g),P2[f>>2]=c-(32<=(63&i)>>>0?o>>s:((1<>>s),(0|(_=_+1|0))==(0|r))break}}else if(9<=i>>>0){if(11<=i>>>0){if(12!=(0|i)){if(!((0|r)<1))for(u=P2[e+-4>>2],_=P2[e+-8>>2],i=P2[e+-12>>2],g=P2[e+-16>>2],o=P2[e+-20>>2],A=P2[e+-24>>2],s=P2[e+-28>>2],c=P2[e+-32>>2],b=P2[e+-36>>2],m=P2[e+-40>>2],k=P2[e+-44>>2],U=(T=f=P2[a>>2])>>31,V=(x=f=P2[a+4>>2])>>31,R=(Y=f=P2[a+8>>2])>>31,S=(O=f=P2[a+12>>2])>>31,M=(G=f=P2[a+16>>2])>>31,P=(Q=f=P2[a+20>>2])>>31,I=(L=f=P2[a+24>>2])>>31,B=(F=f=P2[a+28>>2])>>31,y=(D=f=P2[a+32>>2])>>31,E=(C=f=P2[a+36>>2])>>31,v=(h=a=P2[a+40>>2])>>31,a=0;;)if(d=m,m=b,b=c,c=s,s=A,A=o,o=g,g=i,i=_,_=u,w=(f=a<<2)+n|0,u=P2[e+f>>2],l=b0(d,d>>31,C,E),f=T2,k=b0(k,k>>31,h,v),f=T2+f|0,f=(l=k+l|0)>>>0>>0?f+1|0:f,k=b0(m,m>>31,D,y),f=T2+f|0,f=(l=k+l|0)>>>0>>0?f+1|0:f,k=b0(b,b>>31,F,B),f=T2+f|0,f=(l=k+l|0)>>>0>>0?f+1|0:f,k=b0(c,c>>31,L,I),f=T2+f|0,f=(l=k+l|0)>>>0>>0?f+1|0:f,k=b0(s,s>>31,Q,P),f=T2+f|0,f=(l=k+l|0)>>>0>>0?f+1|0:f,k=b0(A,A>>31,G,M),f=T2+f|0,f=(l=k+l|0)>>>0>>0?f+1|0:f,k=b0(o,o>>31,O,S),f=T2+f|0,f=(l=k+l|0)>>>0>>0?f+1|0:f,k=b0(g,g>>31,Y,R),f=T2+f|0,f=(l=k+l|0)>>>0>>0?f+1|0:f,k=b0(i,i>>31,x,V),f=T2+f|0,f=(l=k+l|0)>>>0>>0?f+1|0:f,k=b0(_,_>>31,T,U),f=T2+f|0,k=f=(l=k+l|0)>>>0>>0?f+1|0:f,p=31&(f=t),P2[w>>2]=u-(32<=(63&f)>>>0?k>>p:((1<>>p),k=d,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(k=P2[e+-4>>2],_=P2[e+-8>>2],i=P2[e+-12>>2],g=P2[e+-16>>2],o=P2[e+-20>>2],A=P2[e+-24>>2],s=P2[e+-28>>2],c=P2[e+-32>>2],b=P2[e+-36>>2],m=P2[e+-40>>2],d=P2[e+-44>>2],f=P2[e+-48>>2],N=(z=u=P2[a>>2])>>31,T=(j=u=P2[a+4>>2])>>31,x=(U=u=P2[a+8>>2])>>31,Y=(V=u=P2[a+12>>2])>>31,O=(R=u=P2[a+16>>2])>>31,G=(S=u=P2[a+20>>2])>>31,Q=(M=u=P2[a+24>>2])>>31,L=(P=u=P2[a+28>>2])>>31,F=(I=u=P2[a+32>>2])>>31,D=(B=u=P2[a+36>>2])>>31,C=(y=u=P2[a+40>>2])>>31,h=(E=a=P2[a+44>>2])>>31,a=0;;)if(u=d,d=m,m=b,b=c,c=s,s=A,A=o,o=g,g=i,i=_,_=k,v=(k=a<<2)+n|0,k=P2[e+k>>2],l=b0(u,u>>31,y,C),p=T2,w=l,l=b0(f,f>>31,E,h),f=T2+p|0,f=(w=w+l|0)>>>0>>0?f+1|0:f,l=b0(d,d>>31,B,D),f=T2+f|0,f=(p=l+w|0)>>>0>>0?f+1|0:f,l=b0(m,m>>31,I,F),f=T2+f|0,f=(p=l+p|0)>>>0>>0?f+1|0:f,l=b0(b,b>>31,P,L),f=T2+f|0,f=(p=l+p|0)>>>0>>0?f+1|0:f,l=b0(c,c>>31,M,Q),f=T2+f|0,f=(p=l+p|0)>>>0>>0?f+1|0:f,l=b0(s,s>>31,S,G),f=T2+f|0,f=(p=l+p|0)>>>0>>0?f+1|0:f,l=b0(A,A>>31,R,O),f=T2+f|0,f=(p=l+p|0)>>>0>>0?f+1|0:f,l=b0(o,o>>31,V,Y),f=T2+f|0,f=(p=l+p|0)>>>0>>0?f+1|0:f,l=b0(g,g>>31,U,x),f=T2+f|0,f=(p=l+p|0)>>>0>>0?f+1|0:f,l=b0(i,i>>31,j,T),f=T2+f|0,f=(p=l+p|0)>>>0>>0?f+1|0:f,l=b0(_,_>>31,z,N),f=T2+f|0,l=f=(p=l+p|0)>>>0>>0?f+1|0:f,w=31&(f=t),P2[v>>2]=k-(32<=(63&f)>>>0?l>>w:((1<>>w),f=u,(0|(a=a+1|0))==(0|r))break}else if(10!=(0|i)){if(!((0|r)<1))for(m=P2[e+-4>>2],_=P2[e+-8>>2],i=P2[e+-12>>2],g=P2[e+-16>>2],o=P2[e+-20>>2],A=P2[e+-24>>2],s=P2[e+-28>>2],c=P2[e+-32>>2],d=P2[e+-36>>2],S=(O=b=P2[a>>2])>>31,M=(G=b=P2[a+4>>2])>>31,P=(Q=b=P2[a+8>>2])>>31,I=(L=b=P2[a+12>>2])>>31,B=(F=b=P2[a+16>>2])>>31,y=(D=b=P2[a+20>>2])>>31,E=(C=b=P2[a+24>>2])>>31,v=(h=b=P2[a+28>>2])>>31,p=(w=a=P2[a+32>>2])>>31,a=0;;)if(b=c,c=s,s=A,A=o,o=g,g=i,i=_,_=m,l=(f=a<<2)+n|0,m=P2[e+f>>2],u=b0(b,b>>31,h,v),f=T2,d=b0(d,d>>31,w,p),f=T2+f|0,f=(u=d+u|0)>>>0>>0?f+1|0:f,d=b0(c,c>>31,C,E),f=T2+f|0,f=(u=d+u|0)>>>0>>0?f+1|0:f,d=b0(s,s>>31,D,y),f=T2+f|0,f=(u=d+u|0)>>>0>>0?f+1|0:f,d=b0(A,A>>31,F,B),f=T2+f|0,f=(u=d+u|0)>>>0>>0?f+1|0:f,d=b0(o,o>>31,L,I),f=T2+f|0,f=(u=d+u|0)>>>0>>0?f+1|0:f,d=b0(g,g>>31,Q,P),f=T2+f|0,f=(u=d+u|0)>>>0>>0?f+1|0:f,d=b0(i,i>>31,G,M),f=T2+f|0,f=(u=d+u|0)>>>0>>0?f+1|0:f,d=b0(_,_>>31,O,S),f=T2+f|0,d=f=(u=d+u|0)>>>0>>0?f+1|0:f,k=31&(f=t),P2[l>>2]=m-(32<=(63&f)>>>0?d>>k:((1<>>k),d=b,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(d=P2[e+-4>>2],_=P2[e+-8>>2],i=P2[e+-12>>2],g=P2[e+-16>>2],o=P2[e+-20>>2],A=P2[e+-24>>2],s=P2[e+-28>>2],c=P2[e+-32>>2],b=P2[e+-36>>2],u=P2[e+-40>>2],Y=(V=f=P2[a>>2])>>31,O=(R=f=P2[a+4>>2])>>31,G=(S=f=P2[a+8>>2])>>31,Q=(M=f=P2[a+12>>2])>>31,L=(P=f=P2[a+16>>2])>>31,F=(I=f=P2[a+20>>2])>>31,D=(B=f=P2[a+24>>2])>>31,C=(y=f=P2[a+28>>2])>>31,h=(E=f=P2[a+32>>2])>>31,w=(v=a=P2[a+36>>2])>>31,a=0;;)if(m=b,b=c,c=s,s=A,A=o,o=g,g=i,i=_,_=d,p=(f=a<<2)+n|0,d=P2[e+f>>2],k=b0(m,m>>31,E,h),f=T2,u=b0(u,u>>31,v,w),f=T2+f|0,f=(k=u+k|0)>>>0>>0?f+1|0:f,u=b0(b,b>>31,y,C),f=T2+f|0,f=(k=u+k|0)>>>0>>0?f+1|0:f,u=b0(c,c>>31,B,D),f=T2+f|0,f=(k=u+k|0)>>>0>>0?f+1|0:f,u=b0(s,s>>31,I,F),f=T2+f|0,f=(k=u+k|0)>>>0>>0?f+1|0:f,u=b0(A,A>>31,P,L),f=T2+f|0,f=(k=u+k|0)>>>0>>0?f+1|0:f,u=b0(o,o>>31,M,Q),f=T2+f|0,f=(k=u+k|0)>>>0>>0?f+1|0:f,u=b0(g,g>>31,S,G),f=T2+f|0,f=(k=u+k|0)>>>0>>0?f+1|0:f,u=b0(i,i>>31,R,O),f=T2+f|0,f=(k=u+k|0)>>>0>>0?f+1|0:f,u=b0(_,_>>31,V,Y),f=T2+f|0,u=f=(k=u+k|0)>>>0>>0?f+1|0:f,l=31&(f=t),P2[p>>2]=d-(32<=(63&f)>>>0?u>>l:((1<>>l),u=m,(0|(a=a+1|0))==(0|r))break}else if(5<=i>>>0){if(7<=i>>>0){if(8!=(0|i)){if(!((0|r)<1))for(c=P2[e+-4>>2],_=P2[e+-8>>2],i=P2[e+-12>>2],g=P2[e+-16>>2],o=P2[e+-20>>2],A=P2[e+-24>>2],b=P2[e+-28>>2],I=(L=s=P2[a>>2])>>31,B=(F=s=P2[a+4>>2])>>31,y=(D=s=P2[a+8>>2])>>31,E=(C=s=P2[a+12>>2])>>31,v=(h=s=P2[a+16>>2])>>31,p=(w=s=P2[a+20>>2])>>31,k=(l=a=P2[a+24>>2])>>31,a=0;;)if(s=A,A=o,o=g,g=i,i=_,_=c,u=(c=a<<2)+n|0,c=P2[e+c>>2],m=b0(s,s>>31,w,p),f=T2,b=b0(b,b>>31,l,k),f=T2+f|0,f=(m=b+m|0)>>>0>>0?f+1|0:f,b=b0(A,A>>31,h,v),f=T2+f|0,f=(m=b+m|0)>>>0>>0?f+1|0:f,b=b0(o,o>>31,C,E),f=T2+f|0,f=(m=b+m|0)>>>0>>0?f+1|0:f,b=b0(g,g>>31,D,y),f=T2+f|0,f=(m=b+m|0)>>>0>>0?f+1|0:f,b=b0(i,i>>31,F,B),f=T2+f|0,f=(m=b+m|0)>>>0>>0?f+1|0:f,b=b0(_,_>>31,L,I),f=T2+f|0,f=(m=b+m|0)>>>0>>0?f+1|0:f,d=31&t,P2[u>>2]=c-(32<=(63&t)>>>0?f>>d:((1<>>d),b=s,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(b=P2[e+-4>>2],_=P2[e+-8>>2],i=P2[e+-12>>2],g=P2[e+-16>>2],o=P2[e+-20>>2],A=P2[e+-24>>2],s=P2[e+-28>>2],m=P2[e+-32>>2],Q=(M=c=P2[a>>2])>>31,L=(P=c=P2[a+4>>2])>>31,F=(I=c=P2[a+8>>2])>>31,D=(B=c=P2[a+12>>2])>>31,C=(y=c=P2[a+16>>2])>>31,h=(E=c=P2[a+20>>2])>>31,w=(v=c=P2[a+24>>2])>>31,l=(p=a=P2[a+28>>2])>>31,a=0;;)if(c=s,s=A,A=o,o=g,g=i,i=_,_=b,k=(b=a<<2)+n|0,b=P2[e+b>>2],d=b0(c,c>>31,v,w),f=T2,m=b0(m,m>>31,p,l),f=T2+f|0,f=(d=m+d|0)>>>0>>0?f+1|0:f,m=b0(s,s>>31,E,h),f=T2+f|0,f=(d=m+d|0)>>>0>>0?f+1|0:f,m=b0(A,A>>31,y,C),f=T2+f|0,f=(d=m+d|0)>>>0>>0?f+1|0:f,m=b0(o,o>>31,B,D),f=T2+f|0,f=(d=m+d|0)>>>0>>0?f+1|0:f,m=b0(g,g>>31,I,F),f=T2+f|0,f=(d=m+d|0)>>>0>>0?f+1|0:f,m=b0(i,i>>31,P,L),f=T2+f|0,f=(d=m+d|0)>>>0>>0?f+1|0:f,m=b0(_,_>>31,M,Q),f=T2+f|0,m=f=(d=m+d|0)>>>0>>0?f+1|0:f,u=31&(f=t),P2[k>>2]=b-(32<=(63&f)>>>0?m>>u:((1<>>u),m=c,(0|(a=a+1|0))==(0|r))break}else if(6!=(0|i)){if(!((0|r)<1))for(A=P2[e+-4>>2],_=P2[e+-8>>2],i=P2[e+-12>>2],g=P2[e+-16>>2],s=P2[e+-20>>2],C=(y=o=P2[a>>2])>>31,h=(E=o=P2[a+4>>2])>>31,w=(v=o=P2[a+8>>2])>>31,l=(p=o=P2[a+12>>2])>>31,u=(k=a=P2[a+16>>2])>>31,a=0;;)if(o=g,g=i,i=_,_=A,d=(A=a<<2)+n|0,A=P2[e+A>>2],b=b0(o,o>>31,p,l),c=T2,s=b0(s,s>>31,k,u),f=T2+c|0,f=(b=s+b|0)>>>0>>0?f+1|0:f,s=b0(g,g>>31,v,w),f=T2+f|0,f=(c=s+b|0)>>>0>>0?f+1|0:f,s=b0(i,i>>31,E,h),f=T2+f|0,f=(c=s+c|0)>>>0>>0?f+1|0:f,s=b0(_,_>>31,y,C),f=T2+f|0,f=(c=s+c|0)>>>0>>0?f+1|0:f,b=31&t,P2[d>>2]=A-(32<=(63&t)>>>0?f>>b:((1<>>b),s=o,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(s=P2[e+-4>>2],_=P2[e+-8>>2],i=P2[e+-12>>2],g=P2[e+-16>>2],o=P2[e+-20>>2],c=P2[e+-24>>2],D=(B=A=P2[a>>2])>>31,C=(y=A=P2[a+4>>2])>>31,h=(E=A=P2[a+8>>2])>>31,w=(v=A=P2[a+12>>2])>>31,l=(p=A=P2[a+16>>2])>>31,u=(k=a=P2[a+20>>2])>>31,a=0;;)if(A=o,o=g,g=i,i=_,_=s,d=(s=a<<2)+n|0,s=P2[e+s>>2],f=b0(A,A>>31,p,l),b=T2,F=(c=b0(c,c>>31,k,u))+f|0,f=T2+b|0,f=F>>>0>>0?f+1|0:f,c=b0(o,o>>31,v,w),f=T2+f|0,f=(b=c+F|0)>>>0>>0?f+1|0:f,c=b0(g,g>>31,E,h),f=T2+f|0,f=(b=c+b|0)>>>0>>0?f+1|0:f,c=b0(i,i>>31,y,C),f=T2+f|0,f=(b=c+b|0)>>>0>>0?f+1|0:f,c=b0(_,_>>31,B,D),f=T2+f|0,f=(b=c+b|0)>>>0>>0?f+1|0:f,m=31&t,P2[d>>2]=s-(32<=(63&t)>>>0?f>>m:((1<>>m),c=A,(0|(a=a+1|0))==(0|r))break}else if(3<=i>>>0){if(4!=(0|i)){if(!((0|r)<1))for(g=P2[e+-4>>2],_=P2[e+-8>>2],o=P2[e+-12>>2],l=(p=i=P2[a>>2])>>31,u=(k=i=P2[a+4>>2])>>31,m=(d=a=P2[a+8>>2])>>31,a=0;;)if(i=_,_=g,b=(g=a<<2)+n|0,c=g=P2[e+g>>2],s=b0(i,i>>31,k,u),A=T2,o=b0(o,o>>31,d,m),f=T2+A|0,f=(s=o+s|0)>>>0>>0?f+1|0:f,o=b0(_,_>>31,p,l),f=T2+f|0,f=(A=o+s|0)>>>0>>0?f+1|0:f,s=31&(o=t),P2[b>>2]=c-(32<=(63&o)>>>0?f>>s:((1<>>s),o=i,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(o=P2[e+-4>>2],_=P2[e+-8>>2],i=P2[e+-12>>2],A=P2[e+-16>>2],v=(h=g=P2[a>>2])>>31,p=(w=g=P2[a+4>>2])>>31,k=(l=g=P2[a+8>>2])>>31,d=(u=a=P2[a+12>>2])>>31,a=0;;)if(g=i,i=_,_=o,m=(o=a<<2)+n|0,o=P2[e+o>>2],c=b0(g,g>>31,l,k),s=T2,A=b0(A,A>>31,u,d),f=T2+s|0,f=(c=A+c|0)>>>0>>0?f+1|0:f,A=b0(i,i>>31,w,p),f=T2+f|0,f=(s=A+c|0)>>>0>>0?f+1|0:f,A=b0(_,_>>31,h,v),f=T2+f|0,f=(s=A+s|0)>>>0>>0?f+1|0:f,c=31&t,P2[m>>2]=o-(32<=(63&t)>>>0?f>>c:((1<>>c),A=g,(0|(a=a+1|0))==(0|r))break}else if(2!=(0|i)){if(!((0|r)<1))for(_=P2[e+-4>>2],s=(c=a=P2[a>>2])>>31,a=0;;)if(f=(i=a<<2)+n|0,g=P2[e+i>>2],_=b0(_,_>>31,c,s),o=T2,A=31&(i=t),P2[f>>2]=g-(32<=(63&i)>>>0?o>>A:((1<>>A),_=g,(0|(a=a+1|0))==(0|r))break}else if(!((0|r)<1))for(i=P2[e+-4>>2],g=P2[e+-8>>2],d=(u=_=P2[a>>2])>>31,b=(m=a=P2[a+4>>2])>>31,a=0;;)if(_=i,c=(i=a<<2)+n|0,i=P2[e+i>>2],A=b0(_,_>>31,u,d),o=T2,g=b0(g,g>>31,m,b),f=T2+o|0,f=(A=g+A|0)>>>0>>0?f+1|0:f,o=A,A=31&t,P2[c>>2]=i-(32<=(63&t)>>>0?f>>A:((1<>>A),g=_,(0|(a=a+1|0))==(0|r))break},Q2[14]=function(e,r,a){e|=0,r|=0,a|=0;var i,t=0,n=0,f=0,o=0,s=0,c=0,u=0,b=0,A=V2(0),k=0,l=0,_=0,d=0,m=0,g=0,p=0,w=0,h=0,v=0;if(V2(0),r)for(v=(_=(o=(f=P2[e+-4>>2])-(c=P2[e+-8>>2])|0)+((u=P2[e+-12>>2])-c|0)|0)+(((u<<1)-c|0)-P2[e+-16>>2]|0)|0,c=u=0;;)if(n=(t=P2[(h<<2)+e>>2])>>31,(s=(n^=t+n)+w|0)>>>0>>0&&(p=p+1|0),w=s,s=(n=t-f|0)>>31,(f=(s^=n+s)+g|0)>>>0>>0&&(d=d+1|0),g=f,f=(s=n-o|0)>>31,(o=(f^=f+s)+m|0)>>>0>>0&&(b=b+1|0),m=o,f=(_=s-_|0)>>31,(o=(f^=f+_)+k|0)>>>0>>0&&(c=c+1|0),k=o,f=(o=_-v|0)>>31,(o=(f^=f+o)+l|0)>>>0>>0&&(u=u+1|0),l=o,f=t,o=n,v=_,_=s,(0|(h=h+1|0))==(0|r))break;return n=(t=(0|b)==(0|d)&g>>>0>>0|d>>>0>>0)?g:m,s=(n=(0|c)==(0|(t=t?d:b))&(e=n)>>>0>>0|t>>>0>>0)?e:k,((e=0)|(t=(n=(0|u)==(0|(t=n?t:c))&s>>>0>>0|t>>>0>>0)?t:u))==(0|p)&w>>>0<(s=n?s:l)>>>0|p>>>0>>0||(n=(t=(0|c)==(0|b)&m>>>0>>0|b>>>0>>0)?m:k,s=(n=(0|u)==(0|(t=t?b:c))&(e=n)>>>0>>0|t>>>0>>0)?e:l,e=1,(0|(t=n?t:u))==(0|d)&g>>>0>>0|d>>>0>>0)||(e=(0|(e=(t=e=(0|c)==(0|u)&k>>>0>>0|c>>>0>>0)?c:u))==(0|b)&m>>>0<(n=t?k:l)>>>0|b>>>0>>0?2:t?3:4),o=a,A=V2(p|w?N0(.6931471805599453*((w>>>0)+4294967296*(p>>>0))/(r>>>0))/.6931471805599453:0),N2[o>>2]=A,o=a,A=V2(d|g?N0(.6931471805599453*((g>>>0)+4294967296*(d>>>0))/(r>>>0))/.6931471805599453:0),N2[o+4>>2]=A,o=a,A=V2(b|m?N0(.6931471805599453*((m>>>0)+4294967296*(b>>>0))/(r>>>0))/.6931471805599453:0),N2[o+8>>2]=A,o=a,A=V2(c|k?N0(.6931471805599453*((k>>>0)+4294967296*(c>>>0))/(r>>>0))/.6931471805599453:0),N2[o+12>>2]=A,u|l?(A=a,i=V2(N0(.6931471805599453*((l>>>0)+4294967296*(u>>>0))/(r>>>0))/.6931471805599453),N2[A+16>>2]=i,0|e):(N2[a+16>>2]=0)|e},Q2[15]=function(e,r,a){e|=0,r|=0,a|=0;var i,t,n,f,o=0,s=V2(0),c=0,u=0,b=0,A=0,k=0,l=0,_=0,d=0,m=0,g=0;if(V2(0),r)for(g=(b=(k=(o=P2[e+-4>>2])-(t=P2[e+-8>>2])|0)+((i=P2[e+-12>>2])-t|0)|0)+(((i<<1)-t|0)-P2[e+-16>>2]|0)|0;;)if(_=((i=(t=P2[(d<<2)+e>>2])>>31)^i+t)+_|0,l=((n=(i=t-o|0)>>31)^i+n)+l|0,A=((o=(n=i-k|0)>>31)^o+n)+A|0,c=((o=(b=n-b|0)>>31)^o+b)+c|0,u=((o=(k=b-g|0)>>31)^o+k)+u|0,o=t,k=i,g=b,b=n,(0|(d=d+1|0))==(0|r))break;return _>>>0<((e=(e=l>>>0>>0?l:A)>>>0>>0?e:c)>>>0>>0?e:u)>>>0||(m=1,l>>>0<((e=A>>>0>>0?A:c)>>>0>>0?e:u)>>>0)||(m=A>>>0<((e=c>>>0>>0)?c:u)>>>0?2:e?3:4),e=a,s=V2(_?N0(.6931471805599453*(_>>>0)/(r>>>0))/.6931471805599453:0),N2[e>>2]=s,e=a,s=V2(l?N0(.6931471805599453*(l>>>0)/(r>>>0))/.6931471805599453:0),N2[e+4>>2]=s,e=a,s=V2(A?N0(.6931471805599453*(A>>>0)/(r>>>0))/.6931471805599453:0),N2[e+8>>2]=s,e=a,s=V2(c?N0(.6931471805599453*(c>>>0)/(r>>>0))/.6931471805599453:0),N2[e+12>>2]=s,u?(s=a,f=V2(N0(.6931471805599453*(u>>>0)/(r>>>0))/.6931471805599453),N2[s+16>>2]=f,0|m):(N2[a+16>>2]=0)|m},Q2[16]=function(e,r,a,i,t,n,f){e|=0,r|=0,t|=0;var o,s=0,c=0,u=0,b=0,A=0,k=0,l=1<(A=1<<(n|=0))>>>0?A:1,c=0-(i|=0)|0,u=(o=(a|=0)+i>>>n|0)-i|0;if((f|=0)+4>>>0<33+(-32^g0(o))>>>0)for(f=0;;){if(s>>>(i=0)<(c=c+o|0)>>>0){for(;;)if(i=((b=(a=P2[(s<<2)+e>>2])>>31)^a+b)+i|0,!((s=s+1|0)>>>0>>0))break;s=u}if(P2[(a=(f<<3)+r|0)>>2]=i,u=u+o|(P2[a+4>>2]=0),(0|l)==(0|(f=f+1|0)))break}else for(a=0;;){if(s>>>(i=k=0)<(c=c+o|0)>>>0){for(;;)if(b=(f=P2[(s<<2)+e>>2])>>31,(f=(b^=f+b)+k|0)>>>0>>0&&(i=i+1|0),k=f,!((s=s+1|0)>>>0>>0))break;s=u}if(P2[(f=(a<<3)+r|0)>>2]=k,P2[f+4>>2]=i,u=u+o|0,(0|l)==(0|(a=a+1|0)))break}if((0|t)<(0|n))for(s=0,e=A;;){if(n=n+-1|0,e=e>>>1|(c=0))for(;;)if(a=P2[(i=(s<<3)+r|0)+8>>2],u=P2[i+12>>2]+P2[i+4>>2]|0,(a=(i=P2[i>>2])+a|0)>>>0>>0&&(u=u+1|0),P2[(f=(A<<3)+r|0)>>2]=a,P2[f+4>>2]=u,s=s+2|0,A=A+1|0,(0|(c=c+1|0))==(0|e))break;if(!((0|t)<(0|n)))break}},Q2[17]=function(e,r,a,i){e|=0,r|=0,a|=0,i|=0;var t,n,f=0,o=0,s=0,c=V2(0),s=r-a|0;if(a)for(n=U2(i,a<<2);;){for(c=N2[(f<<2)+e>>2],o=0;;)if(N2[(t=(o<<2)+n|0)>>2]=N2[t>>2]+V2(c*N2[(f+o<<2)+e>>2]),(0|(o=o+1|0))==(0|a))break;if(!((f=f+1|0)>>>0<=s>>>0))break}else for(;;)if(!((f=f+1|0)>>>0<=s>>>0))break;if(f>>>0>>0)for(;;){if(a=r-f|0)for(c=N2[(f<<2)+e>>2],o=0;;)if(N2[(s=(o<<2)+i|0)>>2]=N2[s>>2]+V2(c*N2[(f+o<<2)+e>>2]),!((o=o+1|0)>>>0>>0))break;if((0|(f=f+1|0))==(0|r))break}},Q2[18]=function(e,r,a,i){e|=0,r|=0,a|=0;var t=0,n=P2[(i|=0)+4>>2];return P2[n+11760>>2]?(P2[a>>2]=4,e=O2[5409]|O2[5410]<<8|(O2[5411]<<16|O2[5412]<<24),s0[0|r]=e,s0[r+1|0]=e>>>8,s0[r+2|0]=e>>>16,s0[r+3|0]=e>>>24,P2[P2[i+4>>2]+11760>>2]=0):(e=P2[n+11812>>2])?(e>>>0<(t=P2[a>>2])>>>0&&(t=P2[a>>2]=e),p0(r,P2[n+11804>>2],t),e=P2[i+4>>2],t=P2[(i=r=e+11804|0)>>2],r=P2[a>>2],P2[i>>2]=t+r,P2[(e=e+11812|0)>>2]=P2[e>>2]-r,0):2},Q2[19]=function(e,r,a,i){e|=0,a|=0;var t,n,f=0,o=0,s=0,c=0,u=0,b=P2[(r|=0)>>2],A=P2[(i|=0)+4>>2];if(e=P2[r+8>>2]){for(f=b<<2;;){if(O0(c=P2[(s=o<<2)+a>>2],u=P2[11764+(A+s|0)>>2],f)){f=0;e:{if(b)for(e=0;;){if((0|(s=P2[(a=e<<2)+c>>2]))!=(0|(a=P2[a+u>>2]))){f=e;break e}if((0|b)==(0|(e=e+1|0)))break}s=a=0}return c=P2[r+28>>2],(t=(e=f)+P2[r+24>>2]|0)>>>0>>0&&(c=c+1|0),P2[(u=A+11816|0)>>2]=t,P2[u+4>>2]=c,e=P2[r+28>>2],r=P2[r+24>>2],P2[A+11840>>2]=s,P2[A+11836>>2]=a,P2[A+11832>>2]=f,P2[A+11828>>2]=o,t=A+11824|0,n=he(r,e,b),P2[t>>2]=n,P2[P2[i>>2]>>2]=4,1}if((0|e)==(0|(o=o+1|0)))break}if(r=P2[(a=A+11800|0)>>2]-b|0,P2[a>>2]=r,e&&(R(f=a=P2[A+11764>>2],f+(a=b<<2)|0,r<<2),(o=1)!=(0|e)))for(;;)if(r=P2[i+4>>2],R(f=P2[11764+(r+(o<<2)|0)>>2],a+f|0,P2[r+11800>>2]<<2),(0|e)==(0|(o=o+1|0)))break}else P2[(e=A+11800|0)>>2]=P2[e>>2]-b;return 0},Q2[20]=function(e,r,a){},Q2[21]=function(e,r,a){P2[P2[(a|=0)>>2]>>2]=3},{__wasm_call_ctors:function(){},FLAC__stream_decoder_new:ee,FLAC__stream_decoder_delete:R0,FLAC__stream_decoder_finish:T0,FLAC__stream_decoder_init_stream:re,FLAC__stream_decoder_reset:x0,FLAC__stream_decoder_init_ogg_stream:function(e,r,a,i,t,n,f,o,s,c){return 0|U0(e|=0,r|=0,a|=0,i|=0,t|=0,n|=0,f|=0,o|=0,s|=0,c|=0,1)},FLAC__stream_decoder_set_ogg_serial_number:function(e,r){return r|=0,e=P2[(e|=0)>>2],0|(e=9==P2[e>>2]?(P2[(e=e+32|0)+4>>2]=r,P2[e>>2]=0,1):0)},FLAC__stream_decoder_set_md5_checking:function(e,r){return r|=0,e=P2[(e|=0)>>2],0|(e=9==P2[e>>2]?(P2[e+28>>2]=r,1):0)},FLAC__stream_decoder_set_metadata_respond:function(e,r){var a=0;return 9!=P2[P2[(e|=0)>>2]>>2]|126<(r|=0)>>>0||(e=P2[e+4>>2],P2[608+(e+(r<<2)|0)>>2]=a=1,2==(0|r)&&(P2[e+1124>>2]=0)),0|a},FLAC__stream_decoder_set_metadata_respond_application:function(e,r){e|=0,r|=0;var a=0,i=0,t=0,a=0;if(9==P2[P2[e>>2]>>2]&&(i=P2[e+4>>2],a=1,!P2[i+616>>2])){a=P2[i+1120>>2];e:{if((0|(t=P2[i+1124>>2]))!=P2[i+1128>>2])i=a;else{r:{if(t){if(t>>>0<=t+t>>>0){if(i=h(a,t<<1))break r;z2(a),i=P2[e+4>>2]}P2[i+1120>>2]=0;break e}i=h(a,0)}if(a=P2[e+4>>2],!(P2[a+1120>>2]=i))break e;P2[a+1128>>2]=P2[a+1128>>2]<<1,t=P2[a+1124>>2]}return a=i,i=P2[1364]>>>3|0,p0(a+G2(i,t)|0,r,i),e=P2[e+4>>2],P2[e+1124>>2]=P2[e+1124>>2]+1,1}P2[P2[e>>2]>>2]=8,a=0}return 0|a},FLAC__stream_decoder_set_metadata_respond_all:function(e){var r;if(9==P2[P2[(e|=0)>>2]>>2]){for(r=P2[e+4>>2],e=0;;)if(128==(0|(e=e+(P2[608+(r+(e<<2)|0)>>2]=1)|0)))break;P2[r+1124>>2]=0,e=1}else e=0;return 0|e},FLAC__stream_decoder_set_metadata_ignore:function(e,r){var a=0;return 9!=P2[P2[(e|=0)>>2]>>2]|126<(r|=0)>>>0||(e=P2[e+4>>2],a=1,2==((P2[608+(e+(r<<2)|0)>>2]=0)|r)&&(P2[e+1124>>2]=0)),0|a},FLAC__stream_decoder_set_metadata_ignore_application:function(e,r){r|=0;var a=0,i=0,t=0;if(9==P2[P2[(e|=0)>>2]>>2]){if(a=P2[e+4>>2],!P2[a+616>>2])return 1;i=P2[a+1120>>2];e:{if((0|(t=P2[a+1124>>2]))!=P2[a+1128>>2])a=i;else{r:{if(t){if(t>>>0<=t+t>>>0){if(a=h(i,t<<1))break r;z2(i),a=P2[e+4>>2]}P2[a+1120>>2]=0;break e}a=h(i,0)}if(i=P2[e+4>>2],!(P2[i+1120>>2]=a))break e;P2[i+1128>>2]=P2[i+1128>>2]<<1,t=P2[i+1124>>2]}return i=a,a=P2[1364]>>>3|0,p0(i+G2(a,t)|0,r,a),e=P2[e+4>>2],P2[e+1124>>2]=P2[e+1124>>2]+1,1}P2[P2[e>>2]>>2]=8}return 0},FLAC__stream_decoder_set_metadata_ignore_all:function(e){return 0|(e=9==P2[P2[(e|=0)>>2]>>2]?(U2(P2[e+4>>2]+608|0,512),P2[P2[e+4>>2]+1124>>2]=0,1):0)},FLAC__stream_decoder_get_state:z0,FLAC__stream_decoder_get_md5_checking:function(e){return P2[P2[(e|=0)>>2]+28>>2]},FLAC__stream_decoder_process_single:j0,FLAC__stream_decoder_process_until_end_of_metadata:function(e){e|=0;var r=0,a=0;e:{r:{for(;;){a:{r=1;i:switch(P2[P2[e>>2]>>2]){case 0:if(H0(e))continue;break a;case 2:case 3:case 4:case 7:break r;case 1:break i;default:break e}if(K0(e))continue}break}r=0}a=r}return 0|a},FLAC__stream_decoder_process_until_end_of_stream:function(e){e|=0;var r,a=0,i=0;R2=r=R2-16|0,a=1;e:{r:{for(;;){a:{i:switch(P2[P2[e>>2]>>2]){case 0:if(H0(e))continue;break a;case 1:if(K0(e))continue;break a;case 2:if(W0(e))continue;break r;case 4:case 7:break r;case 3:break i;default:break e}if(J0(e,12+r|0))continue}break}a=0}i=a}return R2=16+r|0,0|i},FLAC__stream_encoder_new:function(){var e,r,a,i=0;if(a=N(1,8)){if(i=N(1,1032),P2[a>>2]=i)if(r=N(1,11856),P2[a+4>>2]=r){if(i=N(1,20),r=P2[a+4>>2],P2[r+6856>>2]=i)return P2[r+7296>>2]=0,i=P2[a>>2],P2[i+44>>2]=13,P2[i+48>>2]=1056964608,P2[i+36>>2]=0,P2[i+40>>2]=1,P2[i+28>>2]=16,P2[i+32>>2]=44100,P2[i+20>>2]=0,P2[i+24>>2]=2,P2[i+12>>2]=1,P2[i+16>>2]=0,P2[i+4>>2]=0,P2[i+8>>2]=1,i=P2[a>>2],P2[i+592>>2]=0,P2[i+596>>2]=0,P2[i+556>>2]=0,P2[i+560>>2]=0,P2[i+564>>2]=0,P2[i+568>>2]=0,P2[i+572>>2]=0,P2[i+576>>2]=0,P2[i+580>>2]=0,P2[i+584>>2]=0,P2[i+600>>2]=0,P2[i+604>>2]=0,r=P2[a+4>>2],P2[(e=r)+7248>>2]=0,P2[e+7252>>2]=0,P2[e+7048>>2]=0,P2[(e=e+7256|0)>>2]=0,P2[4+e>>2]=0,P2[(e=r+7264|0)>>2]=0,P2[4+e>>2]=0,P2[(e=r+7272|0)>>2]=0,P2[4+e>>2]=0,P2[(e=r+7280|0)>>2]=0,P2[4+e>>2]=0,P2[r+7288>>2]=0,o2(i+632|0),i=P2[a>>2],1==P2[i>>2]&&(P2[i+16>>2]=1,P2[i+20>>2]=0,be(a,10777),i=P2[a>>2],1==P2[i>>2])&&(P2[i+576>>2]=0,P2[i+580>>2]=5,P2[i+564>>2]=0,P2[i+568>>2]=0,P2[i+556>>2]=8,P2[i+560>>2]=0),i=P2[a+4>>2],P2[i+11848>>2]=0,P2[i+6176>>2]=i+336,i=P2[a+4>>2],P2[i+6180>>2]=i+628,i=P2[a+4>>2],P2[i+6184>>2]=i+920,i=P2[a+4>>2],P2[i+6188>>2]=i+1212,i=P2[a+4>>2],P2[i+6192>>2]=i+1504,i=P2[a+4>>2],P2[i+6196>>2]=i+1796,i=P2[a+4>>2],P2[i+6200>>2]=i+2088,i=P2[a+4>>2],P2[i+6204>>2]=i+2380,i=P2[a+4>>2],P2[i+6208>>2]=i+2672,i=P2[a+4>>2],P2[i+6212>>2]=i+2964,i=P2[a+4>>2],P2[i+6216>>2]=i+3256,i=P2[a+4>>2],P2[i+6220>>2]=i+3548,i=P2[a+4>>2],P2[i+6224>>2]=i+3840,i=P2[a+4>>2],P2[i+6228>>2]=i+4132,i=P2[a+4>>2],P2[i+6232>>2]=i+4424,i=P2[a+4>>2],P2[i+6236>>2]=i+4716,i=P2[a+4>>2],P2[i+6240>>2]=i+5008,i=P2[a+4>>2],P2[i+6244>>2]=i+5300,i=P2[a+4>>2],P2[i+6248>>2]=i+5592,i=P2[a+4>>2],P2[i+6252>>2]=i+5884,i=P2[a+4>>2],P2[i+6640>>2]=i+6256,i=P2[a+4>>2],P2[i+6644>>2]=i+6268,i=P2[a+4>>2],P2[i+6648>>2]=i+6280,i=P2[a+4>>2],P2[i+6652>>2]=i+6292,i=P2[a+4>>2],P2[i+6656>>2]=i+6304,i=P2[a+4>>2],P2[i+6660>>2]=i+6316,i=P2[a+4>>2],P2[i+6664>>2]=i+6328,i=P2[a+4>>2],P2[i+6668>>2]=i+6340,i=P2[a+4>>2],P2[i+6672>>2]=i+6352,i=P2[a+4>>2],P2[i+6676>>2]=i+6364,i=P2[a+4>>2],P2[i+6680>>2]=i+6376,i=P2[a+4>>2],P2[i+6684>>2]=i+6388,i=P2[a+4>>2],P2[i+6688>>2]=i+6400,i=P2[a+4>>2],P2[i+6692>>2]=i+6412,i=P2[a+4>>2],P2[i+6696>>2]=i+6424,i=P2[a+4>>2],P2[i+6700>>2]=i+6436,i=P2[a+4>>2],P2[i+6704>>2]=i+6448,i=P2[a+4>>2],P2[i+6708>>2]=i+6460,i=P2[a+4>>2],P2[i+6712>>2]=i+6472,i=P2[a+4>>2],P2[i+6716>>2]=i+6484,n(P2[a+4>>2]+6256|0),n(P2[a+4>>2]+6268|0),n(P2[a+4>>2]+6280|0),n(P2[a+4>>2]+6292|0),n(P2[a+4>>2]+6304|0),n(P2[a+4>>2]+6316|0),n(P2[a+4>>2]+6328|0),n(P2[a+4>>2]+6340|0),n(P2[a+4>>2]+6352|0),n(P2[a+4>>2]+6364|0),n(P2[a+4>>2]+6376|0),n(P2[a+4>>2]+6388|0),n(P2[a+4>>2]+6400|0),n(P2[a+4>>2]+6412|0),n(P2[a+4>>2]+6424|0),n(P2[a+4>>2]+6436|0),n(P2[a+4>>2]+6448|0),n(P2[a+4>>2]+6460|0),n(P2[a+4>>2]+6472|0),n(P2[a+4>>2]+6484|0),n(P2[a+4>>2]+11724|0),n(P2[a+4>>2]+11736|0),P2[P2[a>>2]>>2]=1,0|a;z2(r),z2(P2[a>>2])}else z2(i);z2(a)}return 0},FLAC__stream_encoder_delete:function(e){var r,a=0;(e|=0)&&(P2[P2[e+4>>2]+11848>>2]=1,Ae(e),a=P2[e+4>>2],(r=P2[a+11752>>2])&&(R0(r),a=P2[e+4>>2]),t(a+6256|0),t(P2[e+4>>2]+6268|0),t(P2[e+4>>2]+6280|0),t(P2[e+4>>2]+6292|0),t(P2[e+4>>2]+6304|0),t(P2[e+4>>2]+6316|0),t(P2[e+4>>2]+6328|0),t(P2[e+4>>2]+6340|0),t(P2[e+4>>2]+6352|0),t(P2[e+4>>2]+6364|0),t(P2[e+4>>2]+6376|0),t(P2[e+4>>2]+6388|0),t(P2[e+4>>2]+6400|0),t(P2[e+4>>2]+6412|0),t(P2[e+4>>2]+6424|0),t(P2[e+4>>2]+6436|0),t(P2[e+4>>2]+6448|0),t(P2[e+4>>2]+6460|0),t(P2[e+4>>2]+6472|0),t(P2[e+4>>2]+6484|0),t(P2[e+4>>2]+11724|0),t(P2[e+4>>2]+11736|0),T(P2[P2[e+4>>2]+6856>>2]),z2(P2[e+4>>2]),z2(P2[e>>2]),z2(e))},FLAC__stream_encoder_finish:Ae,FLAC__stream_encoder_init_stream:function(e,r,a,i,t,n){return 0|le(e|=0,0,r|=0,a|=0,i|=0,t|=0,n|=0,0)},FLAC__stream_encoder_init_ogg_stream:function(e,r,a,i,t,n,f){return 0|le(e|=0,r|=0,a|=0,i|=0,t|=0,n|=0,f|=0,1)},FLAC__stream_encoder_set_ogg_serial_number:function(e,r){return r|=0,e=P2[(e|=0)>>2],0|(e=1==P2[e>>2]?(P2[e+632>>2]=r,1):0)},FLAC__stream_encoder_set_verify:function(e,r){return r|=0,e=P2[(e|=0)>>2],0|(e=1==P2[e>>2]?(P2[e+4>>2]=r,1):0)},FLAC__stream_encoder_set_channels:function(e,r){return r|=0,e=P2[(e|=0)>>2],0|(e=1==P2[e>>2]?(P2[e+24>>2]=r,1):0)},FLAC__stream_encoder_set_bits_per_sample:function(e,r){return r|=0,e=P2[(e|=0)>>2],0|(e=1==P2[e>>2]?(P2[e+28>>2]=r,1):0)},FLAC__stream_encoder_set_sample_rate:function(e,r){return r|=0,e=P2[(e|=0)>>2],0|(e=1==P2[e>>2]?(P2[e+32>>2]=r,1):0)},FLAC__stream_encoder_set_compression_level:function(e,r){r|=0;var a,i,t=P2[(e|=0)>>2];return 1==P2[t>>2]?(a=G2(r>>>0<8?r:8,44),i=P2[(r=a+11184|0)+4>>2],P2[t+16>>2]=P2[r>>2],P2[t+20>>2]=i,t=be(e,P2[r+40>>2]),r=0,e=P2[e>>2],e=1==P2[e>>2]?(a=P2[(r=a+11184|0)+32>>2],P2[e+576>>2]=P2[r+28>>2],P2[e+580>>2]=a,P2[e+568>>2]=P2[r+24>>2],P2[e+564>>2]=P2[r+16>>2],a=P2[r+12>>2],P2[e+556>>2]=P2[r+8>>2],P2[e+560>>2]=a,r=1&t,1):0,e&=r):e=0,0|e},FLAC__stream_encoder_set_blocksize:function(e,r){return r|=0,e=P2[(e|=0)>>2],0|(e=1==P2[e>>2]?(P2[e+36>>2]=r,1):0)},FLAC__stream_encoder_set_total_samples_estimate:function(e,r,a){return 0|(r=r|=0,a=a|=0,o=f=0,e=P2[(e=e|=0)>>2],e=1==P2[e>>2]?(t=e,n=r,f=31&(o=P2[1363]),i=-1^(f=32<=(63&o)>>>0?(o=-1<>>32-f|-1<>2]=(r=(0|a)==(0|(f=-1^o))&r>>>0>>0|a>>>0>>0)?n:i,P2[e+596>>2]=r?a:f,1):0);var i,t,n,f,o},FLAC__stream_encoder_set_metadata:function(e,r,a){r|=0,a|=0;var i,t=0,t=P2[(e|=0)>>2];if(1==P2[t>>2]){if((i=P2[t+600>>2])&&(z2(i),t=P2[e>>2],P2[t+600>>2]=0,P2[t+604>>2]=0),a=r?a:0){if(!(t=$2(4,a)))return 0;r=p0(t,r,a<<2),t=P2[e>>2],P2[t+604>>2]=a,P2[t+600>>2]=r}e=t+632|0,e=0!=(0|(e=a>>>P2[1886]?0:(P2[e+4>>2]=a,1)))}else e=0;return 0|e},FLAC__stream_encoder_get_state:z0,FLAC__stream_encoder_get_verify_decoder_state:function(e){return P2[P2[(e|=0)>>2]+4>>2]?0|z0(P2[P2[e+4>>2]+11752>>2]):9},FLAC__stream_encoder_get_verify:function(e){return P2[P2[(e|=0)>>2]+4>>2]},FLAC__stream_encoder_process:function(e,r,a){r|=0,a|=0;var i,t,n,f,o,s=0,c=0,u=0,b=0,A=0,k=0,l=0,_=0,u=P2[(e|=0)>>2],d=(o=P2[u+36>>2])+1|0,c=P2[e+4>>2],m=P2[u+24>>2],g=o<<2;e:{for(;;){if(b=(s=d-P2[c+7052>>2]|0)>>>0<(b=a-A|0)>>>0?s:b,P2[u+4>>2]){if(m)for(u=b<<2,s=0;;)if(p0(P2[11764+((k=s<<2)+c|0)>>2]+(P2[c+11800>>2]<<2)|0,P2[r+k>>2]+(A<<2)|0,u),(0|m)==(0|(s=s+1|0)))break;P2[(c=c+11800|0)>>2]=P2[c>>2]+b}if(m)for(u=b<<2,s=c=0;;){if(!(_=P2[(k=s<<2)+r>>2]))break e;if(l=k,k=P2[e+4>>2],p0(P2[4+(l+k|0)>>2]+(P2[k+7052>>2]<<2)|0,_+(A<<2)|0,u),(0|m)==(0|(s=s+1|0)))break}u=P2[e>>2];r:if(P2[u+16>>2]){if(c=P2[e+4>>2],!(a>>>0<=A>>>0||o>>>0<(s=P2[c+7052>>2])>>>0))for(k=P2[c+40>>2],_=P2[c+36>>2],n=P2[r+4>>2],f=P2[r>>2];;){if(P2[(i=s<<2)+k>>2]=P2[(t=(l=A<<2)+f|0)>>2]-P2[(l=l+n|0)>>2],P2[_+i>>2]=P2[l>>2]+P2[t>>2]>>1,a>>>0<=(A=A+1|0)>>>0)break r;if(!((s=s+1|0)>>>0<=o>>>0))break}}else A=A+b|0,c=P2[e+4>>2];if(s=P2[c+7052>>2]+b|0,o>>>0<(P2[c+7052>>2]=s)>>>0){if(!ke(e,c=0,0))break e;if(m)for(c=P2[e+4>>2],s=0;;)if(b=P2[4+(c+(s<<2)|0)>>2],P2[b>>2]=P2[b+g>>2],(0|m)==(0|(s=s+1|0)))break;c=P2[e+4>>2],u=P2[e>>2],P2[u+16>>2]&&(s=P2[c+36>>2],P2[s>>2]=P2[s+g>>2],s=P2[c+40>>2],P2[s>>2]=P2[s+g>>2]),P2[c+7052>>2]=1}if(!(A>>>0>>0))break}c=1}return 0|c},FLAC__stream_encoder_process_interleaved:function(e,r,a){r|=0,a|=0;var i,t,n=0,f=0,o=0,s=0,c=0,u=0,b=0,A=0,k=0,l=0,_=0,n=P2[(e|=0)>>2],d=(t=P2[n+36>>2])+1|0;e:{r:{if(i=P2[n+24>>2],!(!P2[n+16>>2]|2!=(0|i)))for(;;){if(f=P2[e+4>>2],P2[n+4>>2]){if(n=P2[f+11800>>2],u=(o=d-P2[f+7052>>2]|0)>>>0<(s=a-c|0)>>>0?o:s)if(i){for(o=c<<1,b=P2[f+11768>>2],_=P2[f+11764>>2],s=0;;)if(P2[(k=n<<2)+_>>2]=P2[(l=o<<2)+r>>2],P2[b+k>>2]=P2[(4|l)+r>>2],n=n+1|0,o=o+2|0,(0|u)==(0|(s=s+1|0)))break}else n=n+u|0;P2[f+11800>>2]=n}o=c>>>0>>0,n=P2[f+7052>>2];a:if(!(t>>>0>>0|a>>>0<=c>>>0))for(b=P2[f+40>>2],_=P2[f+8>>2],k=P2[f+36>>2],l=P2[f+4>>2];;){if(s=P2[(u=(A<<2)+r|0)>>2],P2[(o=n<<2)+l>>2]=s,u=P2[u+4>>2],P2[o+_>>2]=u,P2[o+b>>2]=s-u,P2[o+k>>2]=s+u>>1,n=n+1|0,A=A+2|0,o=(c=c+1|0)>>>0>>0,a>>>0<=c>>>0)break a;if(!(n>>>0<=t>>>0))break}if(t>>>0<(P2[f+7052>>2]=n)>>>0){if(!ke(e,n=0,0))break e;n=P2[e+4>>2],s=P2[n+4>>2],P2[(f=s)>>2]=P2[f+(s=t<<2)>>2],f=P2[n+8>>2],P2[f>>2]=P2[f+s>>2],f=P2[n+36>>2],P2[f>>2]=P2[f+s>>2],f=P2[n+40>>2],P2[f>>2]=P2[f+s>>2],P2[n+7052>>2]=1}if(!o)break r;n=P2[e>>2]}for(;;){if(c=P2[e+4>>2],P2[n+4>>2]){if(s=P2[c+11800>>2],u=(n=d-P2[c+7052>>2]|0)>>>0<(o=a-f|0)>>>0?n:o)if(i)for(o=G2(f,i),b=0;;){for(n=0;;)if(P2[P2[11764+(c+(n<<2)|0)>>2]+(s<<2)>>2]=P2[(o<<2)+r>>2],o=o+1|0,(0|i)==(0|(n=n+1|0)))break;if(s=s+1|0,(0|u)==(0|(b=b+1|0)))break}else s=s+u|0;P2[c+11800>>2]=s}s=f>>>0>>0,o=P2[c+7052>>2];a:if(!(t>>>0>>0|a>>>0<=f>>>0)){if(i)for(;;){for(n=0;;)if(P2[P2[4+(c+(n<<2)|0)>>2]+(o<<2)>>2]=P2[(A<<2)+r>>2],A=A+1|0,(0|i)==(0|(n=n+1|0)))break;if(o=o+1|0,s=(f=f+1|0)>>>0>>0,a>>>0<=f>>>0)break a;if(!(o>>>0<=t>>>0))break a}for(;;){if(o=o+1|0,s=(f=f+1|0)>>>0>>0,a>>>0<=f>>>0)break a;if(!(o>>>0<=t>>>0))break}}if(t>>>0<(P2[c+7052>>2]=o)>>>0){if(!ke(e,n=0,0))break e;if(o=P2[e+4>>2],i)for(n=0;;)if(c=P2[4+(o+(n<<2)|0)>>2],P2[c>>2]=P2[c+(t<<2)>>2],(0|i)==(0|(n=n+1|0)))break;P2[o+7052>>2]=1}if(!s)break r;n=P2[e>>2]}}n=1}return 0|n},__errno_location:function(){return 11584},stackSave:function(){return 0|R2},stackRestore:function(e){R2=e|=0},stackAlloc:function(e){return 0|(R2=e=R2-(e|=0)&-16)},malloc:x2,free:z2,__growWasmMemory:function(e){return 0|(e=>{e|=0;var r,a=0|ye();return a<(e=a+e|0)&&e<65536&&(e=new ArrayBuffer(G2(e,65536)),(r=new i.Int8Array(e)).set(s0),s0=r,s0=new i.Int8Array(e),p=new i.Int16Array(e),P2=new i.Int32Array(e),O2=new i.Uint8Array(e),C=new i.Uint16Array(e),S2=new i.Uint32Array(e),N2=new i.Float32Array(e),m0=new i.Float64Array(e),u=e,b.buffer=e),a})(0|(e|=0))},dynCall_iii:function(e,r,a){return 0|Q2[e|=0](r|=0,a|=0)},dynCall_ii:function(e,r){return 0|Q2[e|=0](r|=0)},dynCall_iiii:function(e,r,a,i){return 0|Q2[e|=0](r|=0,a|=0,i|=0)},dynCall_jiji:function(e,r,a,i,t){return e=0|Q2[e|=0](r|=0,a|=0,i|=0,t|=0),L(0|T2),0|e},dynCall_viiiiii:function(e,r,a,i,t,n,f){Q2[e|=0](r|=0,a|=0,i|=0,t|=0,n|=0,f|=0)},dynCall_iiiii:function(e,r,a,i,t){return 0|Q2[e|=0](r|=0,a|=0,i|=0,t|=0)},dynCall_viiiiiii:function(e,r,a,i,t,n,f,o){Q2[e|=0](r|=0,a|=0,i|=0,t|=0,n|=0,f|=0,o|=0)},dynCall_viiii:function(e,r,a,i,t){Q2[e|=0](r|=0,a|=0,i|=0,t|=0)},dynCall_viii:function(e,r,a,i){Q2[e|=0](r|=0,a|=0,i|=0)}};function S(e){var r,a;return(e=(r=P2[3544])+(a=e+3&-4)|0)>>>0<=r>>>0&&1<=(0|a)||e>>>0>ye()<<16>>>0&&!k(0|e)?(P2[2896]=48,-1):(P2[3544]=e,r)}function U2(e,r){var a,i=0;if(r&&(s0[(i=e+r|0)+-1|0]=0,!(r>>>(s0[0|e]=0)<3||(s0[i+-2|0]=0,s0[e+1|0]=0,s0[i+-3|0]=0,r>>>(s0[e+2|0]=0)<7)||(s0[i+-4|0]=0,r>>>(s0[e+3|0]=0)<9)||(P2[(i=(a=0-e&3)+e|0)>>2]=0,(a=r-a&-4)>>>(P2[(r=a+i|0)+-4>>2]=0)<9)||(P2[i+8>>2]=0,P2[i+4>>2]=0,P2[r+-8>>2]=0,a>>>(P2[r+-12>>2]=0)<25)||(P2[i+24>>2]=0,P2[i+20>>2]=0,P2[i+16>>2]=0,P2[i+12>>2]=0,P2[r+-16>>2]=0,P2[r+-20>>2]=0,P2[r+-24>>2]=0,P2[r+-28>>2]=0,(r=(r=a)-(a=4&i|24)|0)>>>0<32))))for(i=i+a|0;;)if(P2[i+24>>2]=0,P2[i+28>>2]=0,P2[i+16>>2]=0,P2[i+20>>2]=0,P2[i+8>>2]=0,P2[i+12>>2]=0,P2[i>>2]=0,i=i+32|(P2[i+4>>2]=0),!(31<(r=r+-32|0)>>>0))break;return e}function p0(e,r,a){var i,t,n=0;if(512<=a>>>0)w(0|e,0|r,0|a);else{if(i=e+a|0,3&(e^r)){if(i>>>0<4)a=e;else if((n=i-4|0)>>>0>>0)a=e;else for(a=e;;)if(s0[0|a]=O2[0|r],s0[a+1|0]=O2[r+1|0],s0[a+2|0]=O2[r+2|0],s0[a+3|0]=O2[r+3|0],r=r+4|0,!((a=a+4|0)>>>0<=n>>>0))break}else{e:if((0|a)<1)a=e;else if(3&e)for(a=e;;){if(s0[0|a]=O2[0|r],r=r+1|0,i>>>0<=(a=a+1|0)>>>0)break e;if(!(3&a))break}else a=e;if(!((n=-4&i)>>>0<64||(t=n+-64|0)>>>0>>0))for(;;)if(P2[a>>2]=P2[r>>2],P2[a+4>>2]=P2[r+4>>2],P2[a+8>>2]=P2[r+8>>2],P2[a+12>>2]=P2[r+12>>2],P2[a+16>>2]=P2[r+16>>2],P2[a+20>>2]=P2[r+20>>2],P2[a+24>>2]=P2[r+24>>2],P2[a+28>>2]=P2[r+28>>2],P2[a+32>>2]=P2[r+32>>2],P2[a+36>>2]=P2[r+36>>2],P2[a+40>>2]=P2[r+40>>2],P2[a+44>>2]=P2[r+44>>2],P2[a+48>>2]=P2[r+48>>2],P2[a+52>>2]=P2[r+52>>2],P2[a+56>>2]=P2[r+56>>2],P2[a+60>>2]=P2[r+60>>2],r=r- -64|0,!((a=a- -64|0)>>>0<=t>>>0))break;if(!(n>>>0<=a>>>0))for(;;)if(P2[a>>2]=P2[r>>2],r=r+4|0,!((a=a+4|0)>>>0>>0))break}if(a>>>0>>0)for(;;)if(s0[0|a]=O2[0|r],r=r+1|0,(0|i)==(0|(a=a+1|0)))break}return e}function x2(e){var r,a=0,i=0,t=0,n=0,f=0,o=0,s=0,c=0,u=0,b=0,A=0;R2=r=R2-16|0;e:{r:{a:{i:{t:{n:{f:{o:{s:{c:{u:{if((e|=0)>>>0<=244){if(3&(a=(o=P2[2897])>>>(e=(f=e>>>0<11?16:e+11&-8)>>>3|0)|0)){e=(a=P2[(f=(i=e+(1&(-1^a))|0)<<3)+11636>>2])+8|0,(0|(t=P2[a+8>>2]))==(0|(f=f+11628|0))?(A=K2(-2,i)&o,P2[11588>>2]=A):(P2[t+12>>2]=f,P2[f+8>>2]=t),P2[a+4>>2]=3|(i<<=3),P2[(a=a+i|0)+4>>2]=1|P2[a+4>>2];break e}if(f>>>0<=(s=P2[2899])>>>0)break u;if(a){i=a=(e=(0-(e=(0-(i=2<>>12&16,a=P2[(t=(i=((i=(i|=a=(e=e>>>a|0)>>>5&8)|(a=(e=e>>>a|0)>>>2&4)|(a=(e=e>>>a|0)>>>1&2))|(a=(e=e>>>a|0)>>>1&1))+(e>>>a|0)|0)<<3)+11636>>2],(0|(e=P2[a+8>>2]))==(0|(t=t+11628|0))?(o=K2(-2,i)&o,P2[2897]=o):(P2[e+12>>2]=t,P2[t+8>>2]=e),e=a+8|0,P2[a+4>>2]=3|f,P2[(n=a+f|0)+4>>2]=1|(t=(i<<=3)-f|0),P2[a+i>>2]=t,s&&(a=11628+((f=s>>>3|0)<<3)|0,i=P2[2902],f=(f=1<>2]:(P2[2897]=f|o,a),P2[a+8>>2]=i,P2[f+12>>2]=i,P2[i+12>>2]=a,P2[i+8>>2]=f),P2[2902]=n,P2[2899]=t;break e}if(!(b=P2[2898]))break u;for(i=a=(e=(b&0-b)-1|0)>>>12&16,a=P2[11892+(((i=(i|=a=(e=e>>>a|0)>>>5&8)|(a=(e=e>>>a|0)>>>2&4)|(a=(e=e>>>a|0)>>>1&2))|(a=(e=e>>>a|0)>>>1&1))+(e>>>a|0)<<2)>>2],t=(-8&P2[a+4>>2])-f|0,i=a;;){if(!(e=(e=P2[i+16>>2])||P2[i+20>>2]))break;t=(i=(n=(-8&P2[e+4>>2])-f|0)>>>0>>0)?n:t,a=i?e:a,i=e}if(u=P2[a+24>>2],(0|(n=P2[a+12>>2]))!=(0|a)){e=P2[a+8>>2],P2[e+12>>2]=n,P2[n+8>>2]=e;break r}if(!(e=P2[(i=a+20|0)>>2])){if(!(e=P2[a+16>>2]))break c;i=a+16|0}for(;;)if(c=i,!((e=P2[(i=(n=e)+20|0)>>2])||(i=n+16|0,e=P2[n+16>>2])))break;P2[c>>2]=0;break r}if(f=-1,!(4294967231>>0)&&(f=-8&(e=e+11|0),c=P2[2898])){i=0-f|0,(e=e>>>8|(s=0))&&(s=31,16777215>>0||(s=28+((e=((o=(a=e<<(t=e+1048320>>>16&8))<<(e=a+520192>>>16&4))<<(a=o+245760>>>16&2)>>>15|0)-(a|e|t)|0)<<1|f>>>e+21&1)|0));b:{A:{if(t=P2[11892+(s<<2)>>2])for(a=f<<(31==(0|s)?0:25-(s>>>1|0)|0),e=0;;){if(!(i>>>0<=(o=(-8&P2[t+4>>2])-f|0)>>>0||(n=t,i=o))){i=0,e=t;break A}if(o=P2[t+20>>2],t=P2[16+((a>>>29&4)+t|0)>>2],e=!o||(0|o)==(0|t)?e:o,a<<=0!=(0|t),!t)break}else e=0;if(!(e|n)){if(!(e=(0-(e=2<>>12&16,e=P2[11892+(((t=(t|=a=(e=e>>>a|0)>>>5&8)|(a=(e=e>>>a|0)>>>2&4)|(a=(e=e>>>a|0)>>>1&2))|(a=(e=e>>>a|0)>>>1&1))+(e>>>a|0)<<2)>>2]}if(!e)break b}for(;;)if(i=(a=(t=(-8&P2[e+4>>2])-f|0)>>>0>>0)?t:i,n=a?e:n,!(e=(a=P2[e+16>>2])||P2[e+20>>2]))break}if(!(!n|i>>>0>=P2[2899]-f>>>0)){if(s=P2[n+24>>2],(0|n)!=(0|(a=P2[n+12>>2]))){e=P2[n+8>>2],P2[e+12>>2]=a,P2[a+8>>2]=e;break a}if(!(e=P2[(t=n+20|0)>>2])){if(!(e=P2[n+16>>2]))break s;t=n+16|0}for(;;)if(o=t,!((e=P2[(t=(a=e)+20|0)>>2])||(t=a+16|0,e=P2[a+16>>2])))break;P2[o>>2]=0;break a}}}if(f>>>0<=(a=P2[2899])>>>0){e=P2[2902],16<=(i=a-f|0)>>>0?(P2[2899]=i,P2[2902]=t=e+f|0,P2[t+4>>2]=1|i,P2[e+a>>2]=i,P2[e+4>>2]=3|f):(P2[2902]=0,P2[2899]=0,P2[e+4>>2]=3|a,P2[(a=e+a|0)+4>>2]=1|P2[a+4>>2]),e=e+8|0;break e}if(f>>>0<(a=P2[2900])>>>0){P2[2900]=a=a-f|0,e=P2[2903],P2[2903]=i=e+f|0,P2[i+4>>2]=1|a,P2[e+4>>2]=3|f,e=e+8|0;break e}if((i=(o=(t=n=f+47|(e=0))+(i=P2[3015]?P2[3017]:(P2[3018]=-1,P2[3019]=-1,P2[3016]=4096,P2[3017]=4096,P2[3015]=12+r&-16^1431655768,P2[3020]=0,P2[3008]=0,4096))|0)&(c=0-i|0))>>>0<=f>>>0)break e;if((t=P2[3007])&&(u=(s=P2[3005])+i|0)>>>0<=s>>>0|t>>>0>>0)break e;if(4&O2[12032])break n;u:{b:{if(t=P2[2903])for(e=12036;;){if((s=P2[e>>2])+P2[e+4>>2]>>>0>t>>>0&&s>>>0<=t>>>0)break b;if(!(e=P2[e+8>>2]))break}if(-1==(0|(a=S(0))))break f;if(o=i,(o=(t=(e=P2[3016])+-1|0)&a?(i-a|0)+(a+t&0-e)|0:o)>>>0<=f>>>0|2147483646>>0)break f;if((e=P2[3007])&&(c=(t=P2[3005])+o|0)>>>0<=t>>>0|e>>>0>>0)break f;if((0|a)!=(0|(e=S(o))))break u;break t}if(2147483646<(o=c&o-a)>>>0)break f;if((0|(a=S(o)))==(P2[e>>2]+P2[e+4>>2]|0))break o;e=a}if(!(-1==(0|e)|f+48>>>0<=o>>>0)){if(2147483646<(a=(a=P2[3017])+(n-o|0)&0-a)>>>0){a=e;break t}if(-1!=(0|S(a))){o=a+o|0,a=e;break t}S(0-o|0);break f}if(-1!=(0|(a=e)))break t;break f}n=0;break r}a=0;break a}if(-1!=(0|a))break t}P2[3008]=4|P2[3008]}if(2147483646>>0)break i;if(a=S(i),(e=S(0))>>>0<=a>>>0|-1==(0|a)|-1==(0|e))break i;if((o=e-a|0)>>>0<=f+40>>>0)break i}e=P2[3005]+o|0,(P2[3005]=e)>>>0>S2[3006]&&(P2[3006]=e);t:{n:{f:{if(t=P2[2903]){for(e=12036;;){if(((i=P2[e>>2])+(n=P2[e+4>>2])|0)==(0|a))break f;if(!(e=P2[e+8>>2]))break}break n}for((e=P2[2901])>>>0<=a>>>0&&e||(P2[2901]=a),e=0,P2[3010]=o,P2[3009]=a,P2[2905]=-1,P2[2906]=P2[3015],P2[3012]=0;;)if(P2[(i=e<<3)+11636>>2]=t=i+11628|0,P2[i+11640>>2]=t,32==(0|(e=e+1|0)))break;P2[2900]=t=(e=o+-40|0)-(i=a+8&7?-8-a&7:0)|0,P2[2903]=i=a+i|0,P2[i+4>>2]=1|t,P2[4+(e+a|0)>>2]=40,P2[2904]=P2[3019];break t}if(!(8&O2[e+12|0]|a>>>0<=t>>>0|t>>>0>>0)){P2[e+4>>2]=n+o,P2[2903]=a=(e=t+8&7?-8-t&7:0)+t|0,i=P2[2900]+o|0,P2[2900]=e=i-e|0,P2[a+4>>2]=1|e,P2[4+(i+t|0)>>2]=40,P2[2904]=P2[3019];break t}}a>>>0<(e=P2[2901])>>>0&&(P2[2901]=a,e=0),i=a+o|0,e=12036;n:{f:{o:{s:{c:{u:{for(;;){if((0|i)==P2[e>>2])break;if(!(e=P2[e+8>>2]))break u}if(!(8&O2[e+12|0]))break c}for(e=12036;;){if((i=P2[e>>2])>>>0<=t>>>0&&t>>>0<(n=i+P2[e+4>>2]|0)>>>0)break s;e=P2[e+8>>2]}}if(P2[e>>2]=a,P2[e+4>>2]=P2[e+4>>2]+o,P2[(s=(a+8&7?-8-a&7:0)+a|0)+4>>2]=3|f,e=((a=i+(i+8&7?-8-i&7:0)|0)-s|0)-f|0,n=f+s|0,(0|a)==(0|t)){P2[2903]=n,e=P2[2900]+e|0,P2[2900]=e,P2[n+4>>2]=1|e;break f}if(P2[2902]==(0|a)){P2[2902]=n,e=P2[2899]+e|0,P2[2899]=e,P2[n+4>>2]=1|e,P2[e+n>>2]=e;break f}if(1==(3&(i=P2[a+4>>2]))){u=-8&i;c:if(i>>>0<=255)t=P2[a+8>>2],f=i>>>3|0,(0|(i=P2[a+12>>2]))==(0|t)?(A=P2[2897]&K2(-2,f),P2[11588>>2]=A):(P2[t+12>>2]=i,P2[i+8>>2]=t);else{if(c=P2[a+24>>2],(0|(o=P2[a+12>>2]))!=(0|a))i=P2[a+8>>2],P2[i+12>>2]=o,P2[o+8>>2]=i;else if((f=P2[(t=a+20|0)>>2])||(f=P2[(t=a+16|0)>>2])){for(;;)if(i=t,!((f=P2[(t=(o=f)+20|0)>>2])||(t=o+16|0,f=P2[o+16>>2])))break;P2[i>>2]=0}else o=0;if(c){i=P2[a+28>>2];u:{if(P2[(t=11892+(i<<2)|0)>>2]==(0|a)){if(P2[t>>2]=o)break u;A=P2[2898]&K2(-2,i),P2[11592>>2]=A;break c}if(!(P2[c+(P2[c+16>>2]==(0|a)?16:20)>>2]=o))break c}P2[o+24>>2]=c,(i=P2[a+16>>2])&&(P2[o+16>>2]=i,P2[i+24>>2]=o),(i=P2[a+20>>2])&&(P2[o+20>>2]=i,P2[i+24>>2]=o)}}a=a+u|0,e=e+u|0}if(P2[a+4>>2]=-2&P2[a+4>>2],P2[n+4>>2]=1|e,(P2[e+n>>2]=e)>>>0<=255){e=11628+((a=e>>>3|0)<<3)|0,a=(i=P2[2897])&(a=1<>2]:(P2[2897]=a|i,e),P2[e+8>>2]=n,P2[a+12>>2]=n,P2[n+12>>2]=e,P2[n+8>>2]=a;break f}if((a=e>>>8|(i=0))&&(i=31,16777215>>0||(i=28+((a=((f=(i=a<<(t=a+1048320>>>16&8))<<(a=i+520192>>>16&4))<<(i=f+245760>>>16&2)>>>15|0)-(i|a|t)|0)<<1|e>>>a+21&1)|0)),a=i,P2[(o=n)+28>>2]=a,P2[n+16>>2]=0,i=11892+(a<<2)|(P2[n+20>>2]=0),(t=P2[2898])&(f=1<>>1|0)|0),a=P2[i>>2];;){if((-8&P2[(i=a)+4>>2])==(0|e))break o;if(a=t>>>29|0,t<<=1,!(a=P2[(f=16+(i+(4&a)|0)|0)>>2]))break}P2[f>>2]=n}else P2[2898]=t|f,P2[i>>2]=n;P2[n+24>>2]=i,P2[n+12>>2]=n,P2[n+8>>2]=n;break f}for(P2[2900]=c=(e=o+-40|0)-(i=a+8&7?-8-a&7:0)|0,P2[2903]=i=a+i|0,P2[i+4>>2]=1|c,P2[4+(e+a|0)>>2]=40,P2[2904]=P2[3019],P2[(i=(e=(n+(n+-39&7?39-n&7:0)|0)-47|0)>>>0>>0?t:e)+4>>2]=27,e=P2[3012],P2[i+16>>2]=P2[3011],P2[i+20>>2]=e,e=P2[3010],P2[i+8>>2]=P2[3009],P2[i+12>>2]=e,P2[3011]=i+8,P2[3010]=o,P2[3009]=a,e=i+24|(P2[3012]=0);;)if(P2[e+4>>2]=7,a=e+8|0,e=e+4|0,!(a>>>0>>0))break;if((0|i)==(0|t))break t;if(P2[i+4>>2]=-2&P2[i+4>>2],P2[t+4>>2]=1|(o=i-t|0),(P2[i>>2]=o)>>>0<=255){e=11628+((a=o>>>3|0)<<3)|0,a=(i=P2[2897])&(a=1<>2]:(P2[2897]=a|i,e),P2[e+8>>2]=t,P2[a+12>>2]=t,P2[t+12>>2]=e,P2[t+8>>2]=a;break t}if(P2[t+16>>2]=0,(e=o>>>8|(a=P2[t+20>>2]=0))&&(a=31,16777215>>0||(a=28+((e=((n=(a=e<<(i=e+1048320>>>16&8))<<(e=a+520192>>>16&4))<<(a=n+245760>>>16&2)>>>15|0)-(a|e|i)|0)<<1|o>>>e+21&1)|0)),e=a,a=11892+((P2[(s=t)+28>>2]=e)<<2)|0,(i=P2[2898])&(n=1<>>1|0)|0),a=P2[a>>2];;){if((0|o)==(-8&P2[(i=a)+4>>2]))break n;if(a=e>>>29|0,e<<=1,!(a=P2[(n=16+(i+(4&a)|0)|0)>>2]))break}P2[n>>2]=t,P2[t+24>>2]=i}else P2[2898]=i|n,P2[a>>2]=t,P2[t+24>>2]=a;P2[t+12>>2]=t,P2[t+8>>2]=t;break t}e=P2[i+8>>2],P2[e+12>>2]=n,P2[i+8>>2]=n,P2[n+24>>2]=0,P2[n+12>>2]=i,P2[n+8>>2]=e}e=s+8|0;break e}e=P2[i+8>>2],P2[e+12>>2]=t,P2[i+8>>2]=t,P2[t+24>>2]=0,P2[t+12>>2]=i,P2[t+8>>2]=e}if(!((e=P2[2900])>>>0<=f>>>0)){P2[2900]=a=e-f|0,e=P2[2903],P2[2903]=i=e+f|0,P2[i+4>>2]=1|a,P2[e+4>>2]=3|f,e=e+8|0;break e}}P2[2896]=48,e=0;break e}a:if(s){e=P2[n+28>>2];i:{if(P2[(t=11892+(e<<2)|0)>>2]==(0|n)){if(P2[t>>2]=a)break i;c=K2(-2,e)&c,P2[2898]=c;break a}if(!(P2[s+(P2[s+16>>2]==(0|n)?16:20)>>2]=a))break a}P2[a+24>>2]=s,(e=P2[n+16>>2])&&(P2[a+16>>2]=e,P2[e+24>>2]=a),(e=P2[n+20>>2])&&(P2[a+20>>2]=e,P2[e+24>>2]=a)}a:if(i>>>0<=15)P2[n+4>>2]=3|(e=i+f|0),P2[(e=e+n|0)+4>>2]=1|P2[e+4>>2];else if(P2[n+4>>2]=3|f,P2[(a=n+f|0)+4>>2]=1|i,(P2[a+i>>2]=i)>>>0<=255)e=11628+((i=i>>>3|0)<<3)|0,i=(t=P2[2897])&(i=1<>2]:(P2[2897]=i|t,e),P2[e+8>>2]=a,P2[i+12>>2]=a,P2[a+12>>2]=e,P2[a+8>>2]=i;else{(e=i>>>8|(t=0))&&(t=31,16777215>>0||(t=28+((e=((o=(t=e<<(f=e+1048320>>>16&8))<<(e=t+520192>>>16&4))<<(t=o+245760>>>16&2)>>>15|0)-(t|e|f)|0)<<1|i>>>e+21&1)|0)),e=t,P2[(s=a)+28>>2]=e,P2[a+16>>2]=0,t=11892+(e<<2)|(P2[a+20>>2]=0);i:{if((f=1<>>1|0)|0),f=P2[t>>2];;){if((-8&P2[(t=f)+4>>2])==(0|i))break i;if(f=e>>>29|0,e<<=1,!(f=P2[(o=16+(t+(4&f)|0)|0)>>2]))break}P2[o>>2]=a}else P2[2898]=f|c,P2[t>>2]=a;P2[a+24>>2]=t,P2[a+12>>2]=a,P2[a+8>>2]=a;break a}e=P2[t+8>>2],P2[e+12>>2]=a,P2[t+8>>2]=a,P2[a+24>>2]=0,P2[a+12>>2]=t,P2[a+8>>2]=e}e=n+8|0;break e}r:if(u){e=P2[a+28>>2];a:{if(P2[(i=11892+(e<<2)|0)>>2]==(0|a)){if(P2[i>>2]=n)break a;A=K2(-2,e)&b,P2[11592>>2]=A;break r}if(!(P2[(P2[u+16>>2]==(0|a)?16:20)+u>>2]=n))break r}P2[n+24>>2]=u,(e=P2[a+16>>2])&&(P2[n+16>>2]=e,P2[e+24>>2]=n),(e=P2[a+20>>2])&&(P2[n+20>>2]=e,P2[e+24>>2]=n)}t>>>0<=15?(P2[a+4>>2]=3|(e=t+f|0),P2[(e=e+a|0)+4>>2]=1|P2[e+4>>2]):(P2[a+4>>2]=3|f,P2[(f=a+f|0)+4>>2]=1|t,P2[t+f>>2]=t,s&&(e=11628+((n=s>>>3|0)<<3)|0,i=P2[2902],o=(n=1<>2]:(P2[2897]=n|o,e),P2[e+8>>2]=i,P2[o+12>>2]=i,P2[i+12>>2]=e,P2[i+8>>2]=o),P2[2902]=f,P2[2899]=t),e=a+8|0}return R2=16+r|0,0|e}function z2(e){var r,a=0,i=0,t=0,n=0,f=0,o=0,s=0;e:if(e|=0){r=(t=e+-8|0)+(e=-8&(i=P2[e+-4>>2]))|0;r:if(!(1&i)){if(!(3&i))break e;if((t=t-(i=P2[t>>2])|0)>>>0>>0<=255)n=P2[t+8>>2],i=i>>>3|0,(0|(a=P2[t+12>>2]))==(0|n)?(s=P2[2897]&K2(-2,i),P2[11588>>2]=s):(P2[n+12>>2]=a,P2[a+8>>2]=n);else{if(o=P2[t+24>>2],(0|(i=P2[t+12>>2]))!=(0|t))a=P2[t+8>>2],P2[a+12>>2]=i,P2[i+8>>2]=a;else if((a=P2[(n=t+20|0)>>2])||(a=P2[(n=t+16|0)>>2])){for(;;)if(f=n,!((a=P2[(n=(i=a)+20|0)>>2])||(n=i+16|0,a=P2[i+16>>2])))break;P2[f>>2]=0}else i=0;if(o){n=P2[t+28>>2];a:{if(P2[(a=11892+(n<<2)|0)>>2]==(0|t)){if(P2[a>>2]=i)break a;s=P2[2898]&K2(-2,n),P2[11592>>2]=s;break r}if(!(P2[o+(P2[o+16>>2]==(0|t)?16:20)>>2]=i))break r}P2[i+24>>2]=o,(a=P2[t+16>>2])&&(P2[i+16>>2]=a,P2[a+24>>2]=i),(a=P2[t+20>>2])&&(P2[i+20>>2]=a,P2[a+24>>2]=i)}}else if(3==(3&(i=P2[4+r>>2])))return P2[2899]=e,P2[4+r>>2]=-2&i,P2[t+4>>2]=1|e,void(P2[e+t>>2]=e)}if(!(r>>>0<=t>>>0)&&1&(i=P2[4+r>>2])){r:{if(!(2&i)){if((0|r)==P2[2903]){if(P2[2903]=t,e=P2[2900]+e|0,P2[2900]=e,P2[t+4>>2]=1|e,P2[2902]!=(0|t))break e;return P2[2899]=0,void(P2[2902]=0)}if((0|r)==P2[2902])return P2[2902]=t,e=P2[2899]+e|0,P2[2899]=e,P2[t+4>>2]=1|e,void(P2[e+t>>2]=e);e=(-8&i)+e|0;a:if(i>>>0<=255)i=i>>>3|0,(0|(a=P2[8+r>>2]))==(0|(n=P2[12+r>>2]))?(s=P2[2897]&K2(-2,i),P2[11588>>2]=s):(P2[a+12>>2]=n,P2[n+8>>2]=a);else{if(o=P2[24+r>>2],(0|r)!=(0|(i=P2[12+r>>2])))a=P2[8+r>>2],P2[a+12>>2]=i,P2[i+8>>2]=a;else if((a=P2[(n=20+r|0)>>2])||(a=P2[(n=16+r|0)>>2])){for(;;)if(f=n,!((a=P2[(n=(i=a)+20|0)>>2])||(n=i+16|0,a=P2[i+16>>2])))break;P2[f>>2]=0}else i=0;if(o){n=P2[28+r>>2];i:{if((0|r)==P2[(a=11892+(n<<2)|0)>>2]){if(P2[a>>2]=i)break i;s=P2[2898]&K2(-2,n),P2[11592>>2]=s;break a}if(!(P2[o+((0|r)==P2[o+16>>2]?16:20)>>2]=i))break a}P2[i+24>>2]=o,(a=P2[16+r>>2])&&(P2[i+16>>2]=a,P2[a+24>>2]=i),(a=P2[20+r>>2])&&(P2[i+20>>2]=a,P2[a+24>>2]=i)}}if(P2[t+4>>2]=1|e,P2[e+t>>2]=e,P2[2902]!=(0|t))break r;return void(P2[2899]=e)}P2[4+r>>2]=-2&i,P2[t+4>>2]=1|e,P2[e+t>>2]=e}if(e>>>0<=255)return i=11628+((e=e>>>3|0)<<3)|0,e=(a=P2[2897])&(e=1<>2]:(P2[2897]=e|a,i),P2[i+8>>2]=t,P2[e+12>>2]=t,P2[t+12>>2]=i,void(P2[t+8>>2]=e);P2[t+16>>2]=0,(n=e>>>8|(a=P2[t+20>>2]=0))&&(a=31,16777215>>0||(a=(i=n)<<(n=n+1048320>>>16&8),a=28+((a=((a<<=o=a+520192>>>16&4)<<(f=a+245760>>>16&2)>>>15|0)-(f|n|o)|0)<<1|e>>>a+21&1)|0)),f=11892+((P2[t+28>>2]=a)<<2)|0;r:{a:{if((n=P2[2898])&(i=1<>>1|0)|0),i=P2[f>>2];;){if((-8&P2[(a=i)+4>>2])==(0|e))break a;if(i=n>>>29|0,n<<=1,!(i=P2[(f=16+(a+(4&i)|0)|0)>>2]))break}P2[f>>2]=t,P2[t+24>>2]=a}else P2[2898]=i|n,P2[f>>2]=t,P2[t+24>>2]=f;P2[t+12>>2]=t,P2[t+8>>2]=t;break r}e=P2[a+8>>2],P2[e+12>>2]=t,P2[a+8>>2]=t,P2[t+24>>2]=0,P2[t+12>>2]=a,P2[t+8>>2]=e}if(e=P2[2905]+-1|0,!(P2[2905]=e)){for(t=12044;;)if(t=(e=P2[t>>2])+8|0,!e)break;P2[2905]=-1}}}}function N(e,r){var a,i=0,i=0;return e&&(i=a=b0(e,0,r,0),(e|r)>>>0<65536||(i=T2?-1:a)),!(e=x2(r=i))|!(3&O2[e+-4|0])||U2(e,r),e}function h(e,r){var a,i;return e?4294967232<=r>>>0?(P2[2896]=48,0):(a=((e,r)=>{var a=0,i=0,t=0,n=0,f=0,o=0,s=0,c=0,u=0,b=0,A=0;o=P2[e+4>>2],n=(i=-8&o)+e|0;e:{if(!(a=3&o)){if(r>>>(a=0)<256)break e;if(r+4>>>0<=i>>>0&&(a=e,i-r>>>0<=P2[3017]<<1>>>0))break e;return 0}if(r>>>0<=i>>>0)(a=i-r|0)>>>0<16||(P2[e+4>>2]=1&o|r|2,P2[(r=e+r|0)+4>>2]=3|a,P2[4+n>>2]=1|P2[4+n>>2],G(r,a));else if(((a=0)|n)==P2[2903]){if((t=i+P2[2900]|0)>>>0<=r>>>0)break e;P2[e+4>>2]=1&o|r|2,a=e+r|0,r=t-r|0,P2[a+4>>2]=1|r,P2[2900]=r,P2[2903]=a}else if((0|n)==P2[2902]){if((t=i+P2[2899]|0)>>>0>>0)break e;16<=(a=t-r|0)>>>0?(P2[e+4>>2]=1&o|r|2,P2[(r=e+r|0)+4>>2]=1|a,P2[(t=e+t|0)>>2]=a,P2[t+4>>2]=-2&P2[t+4>>2]):(P2[e+4>>2]=t|1&o|2,P2[(r=e+t|0)+4>>2]=1|P2[r+4>>2],r=a=0),P2[2902]=r,P2[2899]=a}else{if(2&(f=P2[4+n>>2]))break e;if((s=i+(-8&f)|0)>>>0>>0)break e;u=s-r|0;r:if(f>>>0<=255)a=f>>>3|0,f=P2[8+n>>2],t=P2[12+n>>2],(0|f)==(0|t)?(b=11588,A=P2[2897]&K2(-2,a),P2[b>>2]=A):(P2[f+12>>2]=t,P2[t+8>>2]=f);else{if(c=P2[24+n>>2],i=P2[12+n>>2],(0|n)!=(0|i))a=P2[8+n>>2],P2[a+12>>2]=i,P2[i+8>>2]=a;else if((f=P2[(a=20+n|0)>>2])||(f=P2[(a=16+n|0)>>2])){for(;;)if(t=a,!((f=P2[(a=(i=f)+20|0)>>2])||(a=i+16|0,f=P2[i+16>>2])))break;P2[t>>2]=0}else i=0;if(c){t=P2[28+n>>2];a:{if((0|n)==P2[(a=11892+(t<<2)|0)>>2]){if(P2[a>>2]=i)break a;b=11592,A=P2[2898]&K2(-2,t),P2[b>>2]=A;break r}if(!(P2[((0|n)==P2[c+16>>2]?16:20)+c>>2]=i))break r}P2[i+24>>2]=c,(a=P2[16+n>>2])&&(P2[i+16>>2]=a,P2[a+24>>2]=i),(a=P2[20+n>>2])&&(P2[i+20>>2]=a,P2[a+24>>2]=i)}}u>>>0<=15?(P2[e+4>>2]=1&o|s|2,P2[(r=e+s|0)+4>>2]=1|P2[r+4>>2]):(P2[e+4>>2]=1&o|r|2,P2[(a=e+r|0)+4>>2]=3|u,P2[(r=e+s|0)+4>>2]=1|P2[r+4>>2],G(a,u))}a=e}return a})(e+-8|0,r>>>0<11?16:r+11&-8))?a+8|0:(a=x2(r))?(p0(a,e,(i=(3&(i=P2[e+-4>>2])?-4:-8)+(-8&i)|0)>>>0>>0?i:r),z2(e),a):0:x2(r)}function G(e,r){var a=0,i=0,t=0,n=0,f=0,o=0,s=e+r|0;e:{r:if(!(1&(a=P2[e+4>>2]))){if(!(3&a))break e;if(r=(a=P2[e>>2])+r|0,(0|(e=e-a|0))!=P2[2902])if(a>>>0<=255)t=a>>>3|0,a=P2[e+8>>2],(0|(i=P2[e+12>>2]))==(0|a)?(o=P2[2897]&K2(-2,t),P2[11588>>2]=o):(P2[a+12>>2]=i,P2[i+8>>2]=a);else{if(f=P2[e+24>>2],(0|(a=P2[e+12>>2]))!=(0|e))i=P2[e+8>>2],P2[i+12>>2]=a,P2[a+8>>2]=i;else if((t=P2[(i=e+20|0)>>2])||(t=P2[(i=e+16|0)>>2])){for(;;)if(n=i,!((t=P2[(i=(a=t)+20|0)>>2])||(i=a+16|0,t=P2[a+16>>2])))break;P2[n>>2]=0}else a=0;if(f){i=P2[e+28>>2];a:{if(P2[(t=11892+(i<<2)|0)>>2]==(0|e)){if(P2[t>>2]=a)break a;o=P2[2898]&K2(-2,i),P2[11592>>2]=o;break r}if(!(P2[f+(P2[f+16>>2]==(0|e)?16:20)>>2]=a))break r}P2[a+24>>2]=f,(i=P2[e+16>>2])&&(P2[a+16>>2]=i,P2[i+24>>2]=a),(i=P2[e+20>>2])&&(P2[a+20>>2]=i,P2[i+24>>2]=a)}}else if(3==(3&(a=P2[4+s>>2])))return P2[2899]=r,P2[4+s>>2]=-2&a,P2[e+4>>2]=1|r,void(P2[s>>2]=r)}r:{if(!(2&(a=P2[4+s>>2]))){if((0|s)==P2[2903]){if(P2[2903]=e,r=P2[2900]+r|0,P2[2900]=r,P2[e+4>>2]=1|r,P2[2902]!=(0|e))break e;return P2[2899]=0,void(P2[2902]=0)}if((0|s)==P2[2902])return P2[2902]=e,r=P2[2899]+r|0,P2[2899]=r,P2[e+4>>2]=1|r,void(P2[e+r>>2]=r);r=(-8&a)+r|0;a:if(a>>>0<=255)t=a>>>3|0,(0|(a=P2[8+s>>2]))==(0|(i=P2[12+s>>2]))?(o=P2[2897]&K2(-2,t),P2[11588>>2]=o):(P2[a+12>>2]=i,P2[i+8>>2]=a);else{if(f=P2[24+s>>2],(0|s)!=(0|(a=P2[12+s>>2])))i=P2[8+s>>2],P2[i+12>>2]=a,P2[a+8>>2]=i;else if((t=P2[(i=20+s|0)>>2])||(t=P2[(i=16+s|0)>>2])){for(;;)if(n=i,!((t=P2[(i=(a=t)+20|0)>>2])||(i=a+16|0,t=P2[a+16>>2])))break;P2[n>>2]=0}else a=0;if(f){i=P2[28+s>>2];i:{if((0|s)==P2[(t=11892+(i<<2)|0)>>2]){if(P2[t>>2]=a)break i;o=P2[2898]&K2(-2,i),P2[11592>>2]=o;break a}if(!(P2[f+((0|s)==P2[f+16>>2]?16:20)>>2]=a))break a}P2[a+24>>2]=f,(i=P2[16+s>>2])&&(P2[a+16>>2]=i,P2[i+24>>2]=a),(i=P2[20+s>>2])&&(P2[a+20>>2]=i,P2[i+24>>2]=a)}}if(P2[e+4>>2]=1|r,P2[e+r>>2]=r,P2[2902]!=(0|e))break r;return void(P2[2899]=r)}P2[4+s>>2]=-2&a,P2[e+4>>2]=1|r,P2[e+r>>2]=r}if(r>>>0<=255)return r=11628+((a=r>>>3|0)<<3)|0,a=(i=P2[2897])&(a=1<>2]:(P2[2897]=a|i,r),P2[r+8>>2]=e,P2[a+12>>2]=e,P2[e+12>>2]=r,void(P2[e+8>>2]=a);P2[e+16>>2]=0,(t=r>>>8|(a=P2[e+20>>2]=0))&&(a=31,16777215>>0||(a=28+((a=((s=(t<<=n=t+1048320>>>16&8)<<(a=t+520192>>>16&4))<<(t=245760+s>>>16&2)>>>15|0)-(t|a|n)|0)<<1|r>>>a+21&1)|0)),t=11892+((P2[(i=e)+28>>2]=a)<<2)|0;r:{if((i=P2[2898])&(n=1<>>1|0)|0),a=P2[t>>2];;){if((-8&P2[(t=a)+4>>2])==(0|r))break r;if(a=i>>>29|0,i<<=1,!(a=P2[(n=16+(t+(4&a)|0)|0)>>2]))break}P2[n>>2]=e}else P2[2898]=i|n,P2[t>>2]=e;return P2[e+24>>2]=t,P2[e+12>>2]=e,void(P2[e+8>>2]=e)}r=P2[t+8>>2],P2[r+12>>2]=e,P2[t+8>>2]=e,P2[e+24>>2]=0,P2[e+12>>2]=t,P2[e+8>>2]=r}}function U(e,r,a,i,t,n){var f,o,s=0,c=0;64&n?(i=r,r=31&(t=n+-64|0),32<=(63&t)>>>0?(t=i<>>32-r|a<>>0?(s=f<>>32-i|t<>>0?i>>>t|(n=0):(n=i>>>t|0,((1<>>t),i|=c,t=n|s,n=r,r=31&o,r=32<=(63&o)>>>0?(s=n<>>32-r|a<>2]=r,P2[e+4>>2]=a,P2[e+8>>2]=i,P2[e+12>>2]=t}function x(e,r,a,i,t,n){var f,o=0,s=0,c=0;64&n?(r=31&(a=n+-64|0),r=32<=(63&a)>>>0?t>>>r|(a=0):(a=t>>>r|0,((1<>>r),t=i=0):n&&(s=t,o=31&(c=64-n|0),c=32<=(63&c)>>>0?(s=i<>>32-o|s<>>0?a>>>r|(o=0):(o=a>>>r|0,((1<>>r),r|=c,a=o|s,o=i,i=31&n,i=32<=(63&n)>>>0?t>>>i|(s=0):(s=t>>>i|0,((1<>>i),t=s),P2[e>>2]=r,P2[e+4>>2]=a,P2[e+8>>2]=i,P2[e+12>>2]=t}function V(e,r){var a=0;if(r)for(;;)if(a=O2[1024+(O2[0|e]^a)|0],e=e+1|0,!(r=r+-1|0))break;return a}function Y(e,r,a){var i=0;if(2<=r>>>0)for(;;)if(i=a,a=P2[e>>2],i=C[4352+((255&(i^=a>>>16))<<1)>>1]^C[4864+(i>>>7&510)>>1]^C[3840+(a>>>7&510)>>1]^C[3328+((255&a)<<1)>>1],a=P2[e+4>>2],a=i^C[2816+(a>>>23&510)>>1]^C[2304+(a>>>15&510)>>1]^C[512+(1280+(a>>>7&510)|0)>>1]^C[1280+((255&a)<<1)>>1],e=e+8|0,!(1<(r=r+-2|0)>>>0))break;return r&&(e=P2[e>>2],a=C[2304+((255&(r=e>>>16^a))<<1)>>1]^C[2816+(r>>>7&510)>>1]^C[512+(1280+(e>>>7&510)|0)>>1]^C[1280+((255&e)<<1)>>1]),65535&a}function R(e,r,a){var i=0;e:if((0|e)!=(0|r)){if((r-e|0)-a>>>0<=0-(a<<1)>>>0)return void p0(e,r,a);if(i=3&(e^r),e>>>0>>0){if(!i){if(3&e)for(;;){if(!a)break e;if(s0[0|e]=O2[0|r],r=r+1|0,a=a+-1|0,!(3&(e=e+1|0)))break}if(!(a>>>0<=3))for(;;)if(P2[e>>2]=P2[r>>2],r=r+4|0,e=e+4|0,!(3<(a=a+-4|0)>>>0))break}if(a)for(;;)if(s0[0|e]=O2[0|r],e=e+1|0,r=r+1|0,!(a=a+-1|0))break}else{if(!i){if(e+a&3)for(;;){if(!a)break e;if(s0[0|(i=(a=a+-1|0)+e|0)]=O2[r+a|0],!(3&i))break}if(!(a>>>0<=3))for(;;)if(P2[(a=a+-4|0)+e>>2]=P2[r+a>>2],!(3>>0))break}if(a)for(;;)if(s0[(a=a+-1|0)+e|0]=O2[r+a|0],!a)break}}}function T(e){var r;(r=P2[e>>2])&&z2(r),z2(e)}function z(e){return!(7&O2[e+20|0])}function j(e){return 8-(7&P2[e+20>>2])|0}function E(e,r,a){var i=0,t=0,n=0;e:if(a){r:{for(;;){if(n=P2[e+8>>2],t=P2[e+16>>2],i=P2[e+20>>2],((n-t<<5)+(P2[e+12>>2]<<3)|0)-i>>>0>=a>>>0)break r;if(!H(e))break}return}if(t>>>0>>0){if(i){if(n=P2[e>>2],t=P2[n+(t<<2)>>2]&-1>>>i,a>>>0<(i=32-i|0)>>>0){P2[r>>2]=t>>>i-a,P2[e+20>>2]=P2[e+20>>2]+a;break e}if(P2[r>>2]=t,P2[e+20>>2]=0,P2[e+16>>2]=P2[e+16>>2]+1,a=a-i|0)return i=P2[r>>2]<>2]=i,P2[r>>2]=i|P2[(P2[e+16>>2]<<2)+n>>2]>>>32-a,P2[e+20>>2]=a,1;break e}if(i=P2[P2[e>>2]+(t<<2)>>2],a>>>0<=31){P2[r>>2]=i>>>32-a,P2[e+20>>2]=a;break e}return P2[r>>2]=i,P2[e+16>>2]=P2[e+16>>2]+1,1}(t=P2[P2[e>>2]+(t<<2)>>2],i)?(P2[r>>2]=(t&-1>>>i)>>>32-(a+i|0),P2[e+20>>2]=P2[e+20>>2]+a):(P2[r>>2]=t>>>32-a,P2[e+20>>2]=P2[e+20>>2]+a)}else P2[r>>2]=0;return 1}function H(e){var r,a,i=0,t=0,n=0,f=0,o=0,s=0;if(R2=a=R2-16|0,r=P2[e+16>>2]){if(r>>>0<=(i=P2[e+28>>2])>>>0)n=i;else if(t=P2[e+32>>2]){if(P2[e+28>>2]=n=i+1|0,f=P2[e+24>>2],t>>>0<=31){for(i=P2[P2[e>>2]+(i<<2)>>2];;)if(f=C[1280+((i>>>24-t&255^f>>>8)<<1)>>1]^f<<8&65280,o=t>>>0<24,t=s=t+8|0,!o)break;P2[e+32>>2]=s}P2[e+32>>2]=0,P2[e+24>>2]=f}else n=i;i=Y(P2[e>>2]+(n<<2)|0,r-n|0,C[e+24>>1]),P2[e+28>>2]=0,P2[e+24>>2]=i,R(n=P2[e>>2],n+((i=P2[e+16>>2])<<2)|0,(P2[e+8>>2]-i|0)+(0!=P2[e+12>>2])<<2),P2[e+16>>2]=0,t=P2[e+8>>2]-i|0,P2[e+8>>2]=t}else t=P2[e+8>>2];if(i=P2[e+12>>2],n=(P2[e+4>>2]-t<<2)-i|0,f=0,(P2[12+a>>2]=n)&&(t=(n=P2[e>>2]+(t<<2)|0)+i|0,i&&(i=P2[n>>2],P2[n>>2]=i<<24|i<<8&16711680|i>>>8&65280|i>>>24),Q2[P2[e+36>>2]](t,12+a|0,P2[e+40>>2]))){if(r=P2[12+a>>2],t=P2[e+12>>2],(f=P2[(s=e)+8>>2])>>>0<(n=3+(r+(t+(i=f<<2)|0)|0)>>>2|0)>>>0){for(t=P2[e>>2];;)if(i=P2[(o=t+(f<<2)|0)>>2],P2[o>>2]=i<<8&16711680|i<<24|i>>>8&65280|i>>>24,(0|n)==(0|(f=f+1|0)))break;t=P2[e+12>>2],i=P2[e+8>>2]<<2}P2[s+12>>2]=3&(i=i+(t+r|0)|0),P2[e+8>>2]=i>>>2,f=1}return R2=16+a|0,f}function K(e,r,a){var i,t=0;return E(e,12+(R2=i=R2-16|0)|(t=0),a)&&(P2[r>>2]=((e=1<>2])-e,t=1),R2=16+i|0,e=t}function W(e,r,a){var i,t,n,f=0;R2=n=R2-16|0,t=i=r;e:{if(33<=a>>>0){if(!E(e,12+n|0,a+-32|0))break e;if(!E(e,8+n|0,32))break e;e=P2[12+n>>2],P2[r>>2]=a=0,P2[r+4>>2]=e,r=P2[8+n>>2]|a}else{if(!E(e,8+n|0,a))break e;e=0,r=P2[8+n>>2]}P2[t>>2]=r,P2[i+4>>2]=e,f=1}return R2=16+n|0,f}function J(e,r){var a,i=0,t=0;return E(e,8+(R2=a=R2-16|0)|(P2[8+a>>2]=0),8)&&E(e,12+a|0,8)&&(i=P2[8+a>>2]|P2[12+a>>2]<<8,P2[8+a>>2]=i,E(e,12+a|0,8))&&(i|=P2[12+a>>2]<<16,P2[8+a>>2]=i,E(e,12+a|0,8))&&(e=i|P2[12+a>>2]<<24,P2[8+a>>2]=e,P2[r>>2]=e,t=1),R2=16+a|0,t}function X(e,r){var a,i,t=0,n=0;R2=i=R2-16|0,n=1;e:if(r){r:{if(t=7&P2[e+20>>2]){if(!E(e,8+i|0,t=(t=8-t|0)>>>0>>0?t:r))break r;r=r-t|0}if(t=r>>>3|0){for(;;){a:if(P2[e+20>>2]){if(!E(e,12+i|0,8))break r;if(t=t+-1|0)continue}else{if(3>>0){for(;;){if((a=P2[e+16>>2])>>>0>2])P2[e+16>>2]=a+1,t=t+-4|0;else if(!H(e))break r;if(!(3>>0))break}if(!t)break a}for(;;){if(!E(e,12+i|0,8))break r;if(!(t=t+-1|0))break}}break}r&=7}if(!r)break e;if(E(e,8+i|0,r))break e}n=0}return R2=16+i|0,n}function Z(e,r){var a,i,t=0;R2=i=R2-16|0,t=1;e:if(r){for(;;){r:{if(!P2[e+20>>2]){if(!(r>>>0<4)){for(;;){if((a=P2[e+16>>2])>>>0>2])P2[e+16>>2]=a+1,r=r+-4|0;else if(!H(e))break r;if(!(3>>0))break}if(!r)break e}for(;;){if(!E(e,12+i|0,8))break r;if(!(r=r+-1|0))break}break e}if(E(e,12+i|0,8)){if(r=r+-1|0)continue;break e}}break}t=0}return R2=16+i|0,t}function q(e,r,a){var i,t=0;R2=i=R2-16|0;e:if(a)for(;;){if(!P2[e+20>>2]){if(!(a>>>0<4)){for(;;){if((t=P2[e+16>>2])>>>0>2])P2[e+16>>2]=t+1,t=P2[P2[e>>2]+(t<<2)>>2],s0[0|r]=t=t<<24|t<<8&16711680|t>>>8&65280|t>>>24,s0[r+1|0]=t>>>8,s0[r+2|0]=t>>>16,s0[r+3|0]=t>>>24,a=a+-4|0,r=r+4|0;else if(!H(e)){t=0;break e}if(!(3>>0))break}if(!a){t=1;break e}}for(;;){if(!E(e,12+i|0,8)){t=0;break e}if(s0[0|r]=P2[12+i>>2],r=r+(t=1)|0,!(a=a+-1|0))break}break e}if(!E(e,12+i|0,8)){t=0;break e}if(s0[0|r]=P2[12+i>>2],r=r+(t=1)|0,!(a=a+-1|0))break}else t=1;return R2=16+i|0,t}function $(e,r){var a=0,i=0,t=0;P2[r>>2]=0;e:{for(;;){if((i=P2[e+16>>2])>>>0>=S2[e+8>>2])a=P2[e+20>>2];else for(a=P2[e+20>>2],t=P2[e>>2];;){if(i=P2[t+(i<<2)>>2]<>2],r=g0(i),P2[a>>2]=t+r,a=1+(r+P2[e+20>>2]|0)|0,r=1,(P2[e+20>>2]=a)>>>0<32)break e;return P2[e+20>>2]=0,P2[e+16>>2]=P2[e+16>>2]+1,1}if(P2[r>>2]=32+(P2[r>>2]-a|0),P2[e+20>>2]=a=0,i=P2[e+16>>2]+1|0,!((P2[e+16>>2]=i)>>>0>2]))break}if(a>>>0<(t=P2[e+12>>2]<<3)>>>0){if(i=(P2[P2[e>>2]+(i<<2)>>2]&-1<<32-t)<>2],r=g0(i),P2[a>>2]=t+r,P2[e+20>>2]=1+(r+P2[e+20>>2]|0),1;P2[r>>2]=P2[r>>2]+(t-a|0),P2[e+20>>2]=t}if(!H(e))break}r=0}return r}function e0(e,r,a,i){var t,n,f,o=0,s=0,c=0,u=0,b=0,A=0,k=0,l=0,_=0;R2=f=R2-16|0,t=(a<<2)+r|0;e:if(i)for(o=P2[e+16>>2],a=(A=P2[e+8>>2])>>>0<=o>>>0?1:(k=P2[e>>2],l=P2[e+20>>2],b=P2[k+(o<<2)>>2]<>>0>>0)for(n=32-i|0;;){if(a=o,c=s,b)u=c=g0(b);else for(;;){if(A>>>0<=(a=a+1|0)>>>0)break n;if(b=P2[(a<<2)+k>>2],c=(u=g0(b))+c|0,b)break}if(u=(o=b<>>n|0,i>>>0<=(s=(-1^(P2[8+f>>2]=c))+s&31)>>>0)b=o<>>0<=(o=a+1|0)>>>0)break t;b=(a=P2[(o<<2)+k>>2])<<32-(s=s+n|0),u|=a>>>s}if(P2[12+f>>2]=u,P2[r>>2]=(a=c<>>1^0-(1&a),!((r=r+4|0)>>>0>>0))break}P2[e+16>>2]=((r=o>>>0>>0)&!s)+o,P2[e+20>>2]=32-(s||r<<5),_=1;break e}P2[e+20>>2]=0,P2[e+16>>2]=(a=o+1|0)>>>0>>0?A:a;break a}if(!$(e,8+f|0))break e;c=P2[8+f>>2]+c|0,P2[8+f>>2]=c,s=u=0;break i}P2[e+16>>2]=o,P2[e+20>>2]=0}if(!E(e,12+f|0,i-s|0))break e;if(a=c<>2]|u,a|=P2[12+f>>2]=o,P2[r>>2]=a>>>1^(c=0)-(1&a),k=P2[e>>2],o=P2[e+16>>2],l=P2[e+20>>2],b=P2[k+(o<<2)>>2]<>>0<(A=P2[e+8>>2])>>>0|t>>>0<=(r=r+4|0)>>>0)break r}a=1;continue}a=0}else if(!((0|a)<(_=1)))for(;;){if(!$(e,8+f|0)){_=0;break e}if(a=P2[8+f>>2],P2[r>>2]=a>>>1^0-(1&a),!((r=r+4|0)>>>0>>0))break}return R2=16+f|0,_}function r0(e,r,a){var i,t,n=0,f=0,o=0;P2[(R2=t=R2-240|0)>>2]=e,f=1;e:if(!((0|r)<2))for(n=e;;){if(n=(i=n+-24|0)-P2[((o=r+-2|0)<<2)+a>>2]|0,0<=(0|Q2[1](e,n))&&-1<(0|Q2[1](e,i)))break e;if(e=(f<<2)+t|0,0<=(0|Q2[1](n,i))?(P2[e>>2]=n,o=r+-1|0):n=P2[e>>2]=i,f=f+1|0,(0|o)<2)break e;e=P2[t>>2],r=o}f0(t,f),R2=240+t|0}function a0(e,r){var a=0,i=0,t=e,i=r>>>0<=31?(a=P2[e>>2],P2[e+4>>2]):(a=P2[e+4>>2],P2[e+4>>2]=0,P2[e>>2]=a,r=r+-32|0,0);P2[t+4>>2]=i>>>r,P2[e>>2]=i<<32-r|a>>>r}function i0(e,r,a,i,t){var n,f=0,o=0,s=0;R2=n=R2-240|0,f=P2[r>>2],P2[232+n>>2]=f,r=P2[r+4>>2],P2[n>>2]=e,P2[236+n>>2]=r,o=1;e:{r:{a:{if((r||1!=(0|f))&&(f=e-P2[(a<<2)+t>>2]|0,!((0|Q2[1](f,e))<1))){for(s=!i;;){i:{if(r=f,!(!s|(0|a)<2)){if(i=P2[((a<<2)+t|0)-8>>2],-1<(0|Q2[1](f=e+-24|0,r)))break i;if(-1<(0|Q2[1](f-i|0,r)))break i}if(P2[(o<<2)+n>>2]=r,a0(232+n|0,e=n0(232+n|0)),o=o+1|0,a=e+a|0,!P2[236+n>>2]&&1==P2[232+n>>2])break r;if(f=(e=r)-P2[(a<<2)+t>>2]|(i=0),0<(0|Q2[s=1](f,P2[n>>2])))continue;break a}break}r=e;break r}r=e}if(i)break e}f0(n,o),r0(r,a,t)}R2=240+n|0}function t0(e,r){var a=0,i=0,t=e,i=r>>>0<=31?(a=P2[e+4>>2],P2[e>>2]):(a=P2[e>>2],P2[e+4>>2]=a,r=r+-32|(P2[e>>2]=0),0);P2[t>>2]=i<>2]=a<>>32-r}function n0(e){var r;return(r=we(P2[e>>2]+-1|0))||((e=we(P2[e+4>>2]))?e+32|0:0)}function f0(e,r){var a,i,t,n,f=0,o=0,o=24;R2=n=R2-256|0;e:if(!((0|r)<2))for(f=P2[(t=(r<<2)+e|0)>>2]=n;;){for(p0(f,P2[e>>2],a=o>>>0<256?o:256),f=0;;)if(p0(P2[(i=(f<<2)+e|0)>>2],P2[((f=f+1|0)<<2)+e>>2],a),P2[i>>2]=P2[i>>2]+a,(0|r)==(0|f))break;if(!(o=o-a|0))break e;f=P2[t>>2]}R2=256+n|0}function o0(e){var r,a,i=0,t=0,n=0,f=0,o=0,s=0;if(t=P2[e>>2]){var c,u,b=P2[e+4>>2],A=t,k=0,l=0,_=0;P2[8+(R2=u=R2-208|0)>>2]=1,P2[12+u>>2]=0;e:if(_=G2(A,24)){for(P2[16+u>>2]=24,l=A=P2[20+u>>2]=24,k=2;;)if(c=l+24|0,l=A,P2[(16+u|0)+(k<<2)>>2]=A=A+c|0,k=k+1|0,!(A>>>0<_>>>0))break;if((l=(b+_|0)-24|0)>>>0<=b>>>0)A=k=1;else for(A=k=1;;)if(A=3==(3&k)?(r0(b,A,16+u|0),a0(8+u|0,2),A+2|0):(S2[(16+u|0)+((k=A+-1|0)<<2)>>2]>=l-b>>>0?i0(b,8+u|0,A,0,16+u|0):r0(b,A,16+u|0),1==(0|A)?(t0(8+u|0,1),0):(t0(8+u|0,k),1)),k=1|P2[8+u>>2],P2[8+u>>2]=k,!((b=b+24|0)>>>0>>0))break;for(i0(b,8+u|0,A,0,16+u|0);;){r:{a:{i:{if(!(1!=(0|A)|1!=(0|k))){if(P2[12+u>>2])break i;break e}if(1<(0|A))break a}a0(8+u|0,l=n0(8+u|0)),k=P2[8+u>>2],A=A+l|0;break r}t0(8+u|0,2),P2[8+u>>2]=7^P2[8+u>>2],a0(8+u|0,1),i0((_=b+-24|0)-P2[(16+u|0)+((l=A+-2|0)<<2)>>2]|0,8+u|0,A+-1|0,1,16+u|0),t0(8+u|0,1),k=1|P2[8+u>>2],P2[8+u>>2]=k,i0(_,8+u|0,l,1,16+u|0),A=l}b=b+-24|0}}if(R2=208+u|0,P2[e>>2]){if((t=1)<(i=P2[e>>2])>>>0)for(o=1;;)if(n=(r=P2[e+4>>2])+G2(o,24)|0,-1!=(0|(f=P2[n>>2]))|-1!=(0|(s=P2[n+4>>2]))&&(a=f,f=(r+G2(t,24)|0)-24|0,(0|a)==P2[f>>2]&P2[f+4>>2]==(0|s))||(f=P2[n+4>>2],i=r+G2(t,24)|0,P2[i>>2]=P2[n>>2],P2[i+4>>2]=f,r=P2[n+20>>2],P2[i+16>>2]=P2[n+16>>2],P2[i+20>>2]=r,r=P2[n+12>>2],P2[i+8>>2]=P2[n+8>>2],P2[i+12>>2]=r,t=t+1|0,i=P2[e>>2]),!((o=o+1|0)>>>0>>0))break;if(!(i>>>0<=t>>>0))for(n=P2[e+4>>2];;)if(e=n+G2(t,24)|0,P2[e+16>>2]=0,P2[e+8>>2]=0,P2[e+12>>2]=0,P2[e>>2]=-1,P2[e+4>>2]=-1,(0|i)==(0|(t=t+1|0)))break}}}function W2(e){var r=0,a=0;e:{r:if(a=P2[e+4>>2],r=O2[0|a]){for(;;){if((r+-32&255)>>>0<95){if(r=O2[0|(a=a+1|0)])continue;break r}break}a=0;break e}if(a=1,r=P2[e+8>>2],O2[0|r])for(;;){if(!(e=(e=>{var r,a=0,i=0,t=0,i=1;r:{a:if(128&(a=O2[0|e])){if(!(192!=(224&a)|128!=(192&O2[e+1|0])))return(192!=(254&a))<<1;if(224==(240&a)&&128==(192&(t=O2[e+1|0]))&&128==(192&(r=O2[e+2|0]))){if(i=0,128==(224&t)&&224==(0|a))break a;i:{t:switch(a+-237|0){case 0:if(160!=(224&t))break i;break a;case 2:break t;default:break i}if(191==(0|t)&&190==(254&r))break a}return 3}if(240==(248&a)&&!(128!=(192&(i=O2[e+1|0]))|128!=(192&O2[e+2|0]))&&128==(192&O2[e+3|0]))break r;if(248==(252&a)&&!(128!=(192&(i=O2[e+1|0]))|128!=(192&O2[e+2|0])|(128!=(192&O2[e+3|0])|128!=(192&O2[e+4|0]))))return 248==(0|a)&&128==(248&i)?0:5;i=0,252!=(254&a)||128!=(192&(t=O2[e+1|0]))|128!=(192&O2[e+2|0])|(128!=(192&O2[e+3|0])|128!=(192&O2[e+4|0]))||128==(192&O2[e+5|0])&&(i=252==(0|a)&&128==(252&t)?0:6)}return i}return 240==(0|a)?(128!=(240&i))<<2:4})(r))){a=0;break e}if(!O2[0|(r=e+r|0)])break}}return a}function n(e){P2[e+8>>2]=0,P2[e>>2]=0,P2[e+4>>2]=0}function t(e){var r;(r=P2[e>>2])&&z2(r),(r=P2[e+4>>2])&&z2(r),P2[e+8>>2]=0,P2[e>>2]=0,P2[e+4>>2]=0}function k0(e,r){var a,i,t,n=0,n=1;return S2[e+8>>2]>=r>>>0||((a=h(n=P2[e>>2],i=4<>>0||z2(n),n=0,(P2[e>>2]=a)&&((a=h(t=P2[e+4>>2],i))|29>>0||z2(t),P2[e+4>>2]=a)&&(U2(a,i),P2[e+8>>2]=r,n=1)),n}function J2(e,r){var a,i,t=0;if(e){U2(e+8|0,352),P2[e+24>>2]=1024,a=x2(P2[e+4>>2]=16384),P2[e>>2]=a,t=x2(4096),P2[e+16>>2]=t,i=x2(8192),P2[e+20>>2]=i;e:{if(a){if(t&&i)break e;z2(a),t=P2[e+16>>2]}return t&&z2(t),(r=P2[e+20>>2])&&z2(r),U2(e,360),1}P2[e+336>>2]=r,e=0}else e=-1;return e}function l0(e){var r;e&&((r=P2[e>>2])&&z2(r),(r=P2[e+16>>2])&&z2(r),(r=P2[e+20>>2])&&z2(r),U2(e,360))}function _0(e){var r=0,a=0,i=0,t=0;if(e){if(s0[P2[e>>2]+22|0]=0,s0[P2[e>>2]+23|0]=0,s0[P2[e>>2]+24|0]=0,1<=((s0[P2[e>>2]+25|0]=0)|(i=P2[e+4>>2])))for(t=P2[e>>2];;)if(r=P2[6512+((O2[a+t|0]^r>>>24)<<2)>>2]^r<<8,(0|i)==(0|(a=a+1|0)))break;if(1<=(0|(i=P2[e+12>>2])))for(t=P2[e+8>>2],a=0;;)if(r=P2[6512+((O2[a+t|0]^r>>>24)<<2)>>2]^r<<8,(0|i)==(0|(a=a+1|0)))break;s0[P2[e>>2]+22|0]=r,s0[P2[e>>2]+23|0]=r>>>8,s0[P2[e>>2]+24|0]=r>>>16,s0[P2[e>>2]+25|0]=r>>>24}}function d0(e,r){var a;e:{if(((a=P2[e+24>>2])-r|0)<=P2[e+28>>2]){if((2147483647-r|0)<(0|a))break e;if(!(a=h(P2[e+16>>2],(r=(0|(r=r+a|0))<2147483615?r+32|0:r)<<2)))break e;if(P2[e+16>>2]=a,!(a=h(P2[e+20>>2],r<<3)))break e;P2[e+24>>2]=r,P2[e+20>>2]=a}return}return(r=P2[e>>2])&&z2(r),(r=P2[e+16>>2])&&z2(r),(r=P2[e+20>>2])&&z2(r),U2(e,360),1}function w0(e,r){var a;return P2[8+(R2=a=R2-16|0)>>2]=P2[r>>2],P2[12+a>>2]=P2[r+4>>2],e=((e,r,a,i,t)=>{var n,f,o,s,c,u=0,b=0,A=0,k=0,l=0,b=-1;e:{r:if(e&&(k=P2[e>>2])){if(!r)return 0;for(;;){if((0|(A=P2[4+((u<<3)+r|0)>>2]))<0|(2147483647-A|0)<(0|l))break r;if(l=A+l|0,1==(0|(u=u+1|0)))break}if((u=P2[e+12>>2])&&(A=P2[e+8>>2]-u|0,(P2[e+8>>2]=A)&&R(k,u+k|0,A),P2[e+12>>2]=0),((u=P2[e+4>>2])-l|0)<=P2[e+8>>2]){if((2147483647-l|0)<(0|u))break e;if(!(k=h(P2[e>>2],u=(0|(u=u+l|0))<2147482623?u+1024|0:u)))break e;P2[e>>2]=k,P2[e+4>>2]=u}if(!d0(e,f=(k=(0|l)/255|0)+1|0)){for(b=P2[e+8>>2],u=0;;)if(p0(A=P2[e>>2]+b|0,P2[(b=(u<<3)+r|0)>>2],P2[b+4>>2]),b=P2[e+8>>2]+P2[b+4>>2]|0,P2[e+8>>2]=b,1==(0|(u=u+1|0)))break;if(o=A=P2[e+16>>2],s=r=P2[e+28>>2],(0|l)<=254)b=P2[e+20>>2],u=0;else{for(b=P2[e+20>>2],u=0;;)if(P2[A+((n=r+u|0)<<2)>>2]=255,c=P2[e+356>>2],P2[(n=(n<<3)+b|0)>>2]=P2[e+352>>2],P2[4+n>>2]=c,(0|k)==(0|(u=u+1|0)))break;u=k}P2[o+((u=s+u|0)<<2)>>2]=l-G2(k,255),P2[(u=(u<<3)+b|0)>>2]=i,P2[u+4>>2]=t,P2[e+352>>2]=i,P2[e+356>>2]=t,P2[(i=A+(r<<2)|0)>>2]=256|P2[i>>2],P2[e+28>>2]=r+f,r=P2[e+348>>2],(i=P2[e+344>>2]+1|0)>>>0<1&&(r=r+1|0),P2[e+344>>2]=i,P2[e+348>>2]=r,b=0,a&&(P2[e+328>>2]=1)}}return b}return(r=P2[e>>2])&&z2(r),(r=P2[e+16>>2])&&z2(r),(r=P2[e+20>>2])&&z2(r),U2(e,360),-1})(e,8+a|0,P2[r+12>>2],P2[r+16>>2],P2[r+20>>2]),R2=16+a|0,e}function h0(e,r,a){var i,t,n,f=0,o=0,s=0,c=0,u=0,b=0,A=0,k=0,l=0;e:if(e&&(o=(0|(i=P2[e+28>>2]))<255?i:255)&&(t=P2[e>>2])){r:{a:{i:{if(A=P2[e+332>>2]){if(1<=(0|i))break i;s=u=-1;break a}for(f=0<(0|o)?o:0;;){if((0|f)==(0|c))break a;if(b=c<<2,c=o=c+1|0,255!=O2[b+P2[e+16>>2]|0])break}f=o;break a}o=1<(0|o)?o:1,s=u=-1;i:{for(;;){if(!((0|c)<=4096|(0|b)<=3)){a=1;break i}if(255!=((b=0)|(n=O2[P2[e+16>>2]+(f<<2)|0]))&&(b=k=k+1|0,s=P2[e+20>>2]+(f<<3)|0,u=P2[s>>2],s=P2[s+4>>2]),c=c+n|0,(0|o)==(0|(f=f+1|0)))break}f=o}if((o=255)==(0|f))break r}if(o=f,!a)break e}if(P2[e+40>>2]=1399285583,p[e+44>>1]=0,a=P2[e+16>>2],f=1&(-1^O2[a+1|0]),s0[e+45|0]=f=A?f:2|f,!P2[e+328>>2]|(0|o)!=(0|i)||(s0[e+45|0]=4|f),P2[e+332>>2]=1,s0[e+53|0]=s>>>24,s0[e+52|0]=s>>>16,s0[e+51|0]=s>>>8,s0[e+50|0]=s,s0[e+49|0]=(16777215&s)<<8|u>>>24,s0[e+48|0]=(65535&s)<<16|u>>>16,s0[e+47|0]=(255&s)<<24|u>>>8,s0[e+46|0]=u,f=P2[e+336>>2],s0[e+54|0]=f,s0[e+55|0]=f>>>8,s0[e+56|0]=f>>>16,s0[e+57|0]=f>>>24,-1==(0|(f=P2[e+340>>2]))&&(f=P2[e+340>>2]=0),s0[e+66|0]=o,p[e+62>>1]=c=0,p[e+64>>1]=0,s0[e+61|0]=f>>>24,s0[e+60|0]=f>>>16,s0[e+59|0]=f>>>8,s0[e+58|0]=f,P2[e+340>>2]=f+(l=1),1<=(0|o))for(f=0;;)if(s=P2[a+(f<<2)>>2],c=(255&(s0[67+(e+f|0)|0]=s))+c|0,(0|o)==(0|(f=f+1|0)))break;if(P2[r>>2]=e+40,P2[e+324>>2]=f=o+27|0,P2[r+4>>2]=f,f=P2[e+12>>2],P2[r+12>>2]=c,P2[r+8>>2]=f+t,R(a,a+(o<<2)|0,(P2[e+28>>2]=f=i-o|0)<<2),R(a=P2[e+20>>2],a+(o<<3)|0,P2[e+28>>2]<<3),P2[e+12>>2]=P2[e+12>>2]+c,r){if(s0[P2[r>>2]+22|(e=0)]=0,s0[P2[r>>2]+23|0]=0,s0[P2[r>>2]+24|0]=0,1<=((s0[P2[r>>2]+25|0]=0)|(a=P2[r+4>>2])))for(o=P2[r>>2],f=0;;)if(e=P2[6512+((O2[f+o|0]^e>>>24)<<2)>>2]^e<<8,(0|a)==(0|(f=f+1|0)))break;if(1<=(0|(a=P2[r+12>>2])))for(o=P2[r+8>>2],f=0;;)if(e=P2[6512+((O2[f+o|0]^e>>>24)<<2)>>2]^e<<8,(0|a)==(0|(f=f+1|0)))break;s0[P2[r>>2]+22|0]=e,s0[P2[r>>2]+23|0]=e>>>8,s0[P2[r>>2]+24|0]=e>>>16,s0[P2[r>>2]+25|0]=e>>>24}}return l}function v0(e,r){var a,i,t,n,f=0,o=0,s=0,c=0,u=0,b=0;R2=n=R2-16|0;e:if(!(P2[e+4>>2]<0)){o=P2[e+12>>2],i=P2[e+8>>2]-o|0,a=o+P2[e>>2]|0;r:{a:{i:{t:{if(!(s=P2[e+20>>2])){if((0|i)<27)break e;if(1399285583!=(O2[0|a]|O2[1+a|0]<<8|(O2[2+a|0]<<16|O2[3+a|0]<<24)))break t;if((0|i)<(0|(s=(o=O2[26+a|0])+27|0)))break e;if(o)for(o=P2[e+24>>2];;)if(o=O2[27+(a+c|0)|0]+o|0,P2[e+24>>2]=o,!((c=c+1|0)>>>0>2]=s}if((P2[e+24>>2]+s|0)>(0|i))break e;if(u=O2[22+a|0]|O2[23+a|0]<<8|(O2[24+a|0]<<16|O2[25+a|0]<<24),P2[12+n>>2]=u,s0[22+a|(c=0)]=0,s0[23+a|0]=0,s0[24+a|0]=0,s0[25+a|0]=0,t=P2[e+24>>2],b=P2[e+20>>2],s0[22+a|0]=0,s0[23+a|0]=0,s0[24+a|0]=0,(s0[25+a|0]=0)<(0|b))for(s=0;;)if(f=P2[6512+((O2[a+s|0]^f>>>24)<<2)>>2]^f<<8,(0|b)==(0|(s=s+1|0)))break;if(o=22+a|0,0<(0|t))for(b=a+b|0;;)if(f=P2[6512+((O2[c+b|0]^f>>>24)<<2)>>2]^f<<8,(0|t)==(0|(c=c+1|0)))break;if(s0[22+a|0]=f,s0[23+a|0]=f>>>8,s0[24+a|0]=f>>>16,s0[25+a|0]=f>>>24,P2[12+n>>2]==(O2[0|o]|O2[o+1|0]<<8|(O2[o+2|0]<<16|O2[o+3|0]<<24)))break i;s0[0|o]=u,s0[o+1|0]=u>>>8,s0[o+2|0]=u>>>16,s0[o+3|0]=u>>>24}if(P2[e+20>>2]=0,!(f=((e,r)=>{var a=0,a=0!=(0|r);t:{n:{f:if(!(!r|!(3&e)))for(;;){if(79==O2[0|e])break n;if(e=e+1|0,a=0!=(0|(r=r+-1|0)),!r)break f;if(!(3&e))break}if(!a)break t}n:if(!(79==O2[0|e]|r>>>0<4))for(;;){if((-1^(a=1330597711^P2[e>>2]))&a+-16843009&-2139062144)break n;if(e=e+4|0,!(3<(r=r+-4|0)>>>0))break}if(r)for(;;){if(79==O2[0|e])return e;if(e=e+1|0,!(r=r+-1|0))break}}return 0})(1+a|(P2[e+24>>2]=0),i-1|0)))break a;c=P2[e>>2];break r}u=P2[e+12>>2],r?(o=u+P2[e>>2]|0,P2[r>>2]=o,f=P2[e+20>>2],P2[r+4>>2]=f,P2[r+8>>2]=f+o,s=P2[e+24>>2],P2[r+12>>2]=s):(s=P2[e+24>>2],f=P2[e+20>>2]),P2[e+24>>2]=0,P2[e+16>>2]=0,P2[e+20>>2]=0,P2[e+12>>2]=u+(f=f+s|0);break e}f=(c=P2[e>>2])+P2[e+8>>2]|0}P2[e+12>>2]=f-c,f=a-f|0}return R2=16+n|0,f}function y0(e){P2[e+4>>2]<0||(P2[e+8>>2]=0,P2[e+12>>2]=0,P2[e+24>>2]=0,P2[e+16>>2]=0,P2[e+20>>2]=0)}function C0(e){!e|!P2[e>>2]||(P2[e+344>>2]=0,P2[e+348>>2]=0,P2[e+340>>2]=-1,P2[e+332>>2]=0,P2[e+324>>2]=0,P2[e+328>>2]=0,P2[e+36>>2]=0,P2[e+28>>2]=0,P2[e+32>>2]=0,P2[e+8>>2]=0,P2[e+12>>2]=0,P2[e+352>>2]=0,P2[e+356>>2]=0)}function E0(e){var r,a=0;e:J2(e+8|0,P2[e+4>>2])||((r=e+368|0)&&(P2[r>>2]=0,P2[r+4>>2]=0,P2[r+24>>2]=0,P2[r+16>>2]=0,P2[r+20>>2]=0,P2[r+8>>2]=0,P2[r+12>>2]=0),P2[e+396>>2]=-1,P2[e+400>>2]=-1,P2[e+408>>2]=0,P2[e+412>>2]=0,P2[e+404>>2]=P2[e>>2],a=1);return a}function F0(e){P2[e>>2]=1}function B0(e,r,a,i,t){var n,f,o,s,c,u,b,A,k,l,_,d,m,g=0,p=0,w=0;R2=k=R2-16|0,n=P2[a>>2],P2[a>>2]=0;e:{r:{a:if(n)for(f=e+416|0,o=e+368|0,c=e+440|0,u=e+8|0,b=P2[2721],A=O2[7536];;){if(P2[e+408>>2])break a;i:{t:{if(P2[e+412>>2]){if(P2[e+432>>2]){if(w=P2[e+440>>2],(g=n-g|0)>>>0<(p=P2[e+444>>2])>>>0)break t;r=p0(r,w,p),P2[a>>2]=p+P2[a>>2],r=r+p|(P2[e+432>>2]=0);break i}if(1<=(0|(g=((e,r)=>{var a,i=0,t=0,n=0,f=0,o=0,s=0;if(e&&(a=P2[e>>2])&&(f=P2[e+36>>2],!(P2[e+32>>2]<=(0|f)))){if(t=P2[e+16>>2],1024&(o=P2[t+(f<<2)>>2]))return P2[e+36>>2]=f+1,i=P2[(t=r=e)+348>>2],(e=P2[e+344>>2]+1|0)>>>0<1&&(i=i+1|0),P2[t+344>>2]=e,P2[r+348>>2]=i,-1;if(n=512&o,(s=255)!=(0|(i=255&o)))s=i;else for(;;)if(n=512&(i=P2[((f=f+1|0)<<2)+t>>2])?512:n,s=(i&=255)+s|0,255!=(0|i))break;r?(P2[r+8>>2]=256&o,P2[r+12>>2]=n,o=P2[e+12>>2],P2[r>>2]=a+o,i=t=P2[e+348>>2],n=P2[e+344>>2],P2[r+24>>2]=n,P2[r+28>>2]=i,t=P2[e+20>>2]+(f<<3)|0,a=P2[t+4>>2],t=P2[t>>2],P2[r+4>>2]=s,P2[r+16>>2]=t,P2[r+20>>2]=a):(n=P2[e+344>>2],i=P2[e+348>>2],o=P2[e+12>>2]),(t=n+1|0)>>>0<1&&(i=i+1|0),P2[e+344>>2]=t,P2[e+348>>2]=i,P2[e+36>>2]=f+(n=1),P2[e+12>>2]=o+s}return n})(u,c)))){if(P2[e+432>>2]=1,(0|(s=P2[e+444>>2]))<1)break i;if(p=P2[c>>2],O2[0|p]!=(0|A))break i;if(w=3,(0|s)<9)break e;if((O2[p+1|0]|O2[p+2|0]<<8|(O2[p+3|0]<<16|O2[p+4|0]<<24))!=(O2[0|(g=b)]|O2[g+1|0]<<8|(O2[g+2|0]<<16|O2[g+3|0]<<24)))break e;if(g=O2[p+5|0],P2[e+396>>2]=g,P2[e+400>>2]=O2[p+6|0],1!=(0|g)){w=4;break e}P2[e+444>>2]=s+-9,P2[e+440>>2]=p+9;break i}if(g){w=2;break e}P2[e+412>>2]=0;break i}if(1<=(0|(g=((e,r)=>{var a;if(0<=P2[e+4>>2]){for(;;){if(0<(0|(a=v0(e,r))))return 1;if(!a)return 0;if(!P2[e+16>>2])break}e=-(P2[e+16>>2]=1)}else e=0;return e})(o,f)))){if(P2[e+404>>2]&&(m=P2[(m=f)>>2],g=O2[m+14|0]|O2[m+15|0]<<8|(O2[m+16|0]<<16|O2[m+17|0]<<24),P2[e+404>>2]=0,P2[e+344>>2]=g,P2[e+4>>2]=g),((e,r)=>{var a,i,t,n,f,o,s,c=0,u=0,b=0,A=0,k=0,l=0,_=0,u=-1;n:{if(e&&(A=P2[e>>2])&&(a=P2[r>>2],t=O2[a+5|0],b=P2[r+12>>2],_=P2[r+8>>2],i=O2[a+26|0],f=O2[a+18|0]|O2[a+19|0]<<8|(O2[a+20|0]<<16|O2[a+21|0]<<24),l=O2[a+14|0]|O2[a+15|0]<<8|(O2[a+16|0]<<16|O2[a+17|0]<<24),o=O2[a+6|0]|O2[a+7|0]<<8|(O2[a+8|0]<<16|O2[a+9|0]<<24),s=O2[a+10|0]|O2[a+11|0]<<8|(O2[a+12|0]<<16|O2[a+13|0]<<24),n=O2[a+4|0],c=P2[e+36>>2],(r=P2[e+12>>2])&&(k=P2[e+8>>2]-r|0,(P2[e+8>>2]=k)&&R(A,r+A|0,k),P2[e+12>>2]=0),c&&(k=(A=P2[(r=e)+28>>2]-c|0)?(R(k=P2[e+16>>2],k+(c<<2)|0,A<<2),R(A=P2[e+20>>2],A+(c<<3)|0,P2[e+28>>2]-c<<3),P2[e+28>>2]-c|0):0,P2[r+28>>2]=k,P2[e+36>>2]=0,P2[e+32>>2]=P2[e+32>>2]-c),!((0|l)!=P2[e+336>>2]|n||d0(e,i+1|0)))){if(k=1&t,(0|(A=P2[e+340>>2]))!=(0|f)){if((0|(c=P2[e+32>>2]))<(0|(l=P2[e+28>>2]))){for(u=P2[e+8>>2],n=P2[e+16>>2],r=c;;)if(u=u-O2[n+(r<<2)|0]|0,!((0|(r=r+1|0))<(0|l)))break;P2[e+8>>2]=u}P2[e+28>>2]=c,-1!=(0|A)&&(P2[e+28>>2]=r=c+1|0,P2[P2[e+16>>2]+(c<<2)>>2]=1024,P2[e+32>>2]=r)}A=2&t,u=0;f:if(k&&(r=P2[e+28>>2],!(1024!=P2[(P2[e+16>>2]+(r<<2)|0)-4>>2]&&1<=(0|r)))&&(A=0,i)){for(r=0;;){if(u=r+1|0,b=b-(r=O2[27+(r+a|0)|0])|0,_=r+_|0,255!=(0|r))break f;if((0|i)==(0|(r=u)))break}u=i}if(b){if(c=P2[e+4>>2],(0|(r=P2[e+8>>2]))<(c-b|0))c=P2[e>>2];else{if((2147483647-b|0)<(0|c))break n;if(!(c=h(P2[e>>2],r=(0|(r=c+b|0))<2147482623?r+1024|0:r)))break n;P2[e>>2]=c,P2[e+4>>2]=r,r=P2[e+8>>2]}p0(r+c|0,_,b),P2[e+8>>2]=P2[e+8>>2]+b}if(_=4&t,!((0|i)<=(0|u))){if(t=P2[e+20>>2],k=P2[e+16>>2],c=P2[e+28>>2],b=O2[27+(a+u|0)|0],P2[(r=k+(c<<2)|0)>>2]=b,P2[(l=t+(c<<3)|0)>>2]=-1,P2[l+4>>2]=-1,A&&(P2[r>>2]=256|b),P2[e+28>>2]=r=c+1|0,u=u+1|0,255==(0|b)?c=-1:P2[e+32>>2]=r,(0|u)!=(0|i))for(;;)if(A=O2[27+(a+u|0)|0],P2[k+(r<<2)>>2]=A,P2[(b=t+(r<<3)|0)>>2]=-1,P2[b+4>>2]=-1,P2[e+28>>2]=b=r+1|0,u=u+1|0,255!=(0|A)&&(P2[e+32>>2]=b,c=r),r=b,(0|u)==(0|i))break;-1!=(0|c)&&(r=P2[e+20>>2]+(c<<3)|0,P2[r>>2]=o,P2[r+4>>2]=s)}_&&(P2[e+328>>2]=1,(0|(r=P2[e+28>>2]))<1||(r=(P2[e+16>>2]+(r<<2)|0)-4|0,P2[r>>2]=512|P2[r>>2])),P2[e+340>>2]=1+f,u=0}return u}return(r=P2[e>>2])&&z2(r),(r=P2[e+16>>2])&&z2(r),(r=P2[e+20>>2])&&z2(r),U2(e,360),1})(u,f))break i;P2[e+432>>2]=0,P2[e+412>>2]=1;break i}if(g){w=2;break e}if(!(p=((e,r)=>{var a,i=0,t=0;if(0<=(0|(i=P2[e+4>>2]))){if((a=P2[e+12>>2])&&(t=P2[e+8>>2]-a|0,1<=(0|(P2[e+8>>2]=t))&&(R(i=P2[e>>2],i+a|0,t),i=P2[e+4>>2]),P2[e+12>>2]=0),(0|r)<=((t=i)-(i=P2[e+8>>2])|0))r=P2[e>>2];else{if(i=4096+(r+i|0)|0,!(r=(r=P2[e>>2])?h(r,i):x2(i)))return(r=P2[e>>2])&&z2(r),P2[e>>2]=0,P2[e+4>>2]=0,P2[e+24>>2]=0,P2[e+16>>2]=0,P2[e+20>>2]=0,P2[e+8>>2]=0,P2[e+12>>2]=0;P2[e+4>>2]=i,P2[e>>2]=r,i=P2[e+8>>2]}e=r+i|0}else e=0;return e})(o,g=8192<(g=n-P2[a>>2]|0)>>>0?g:8192))){w=7;break e}P2[12+k>>2]=g;n:switch((0|Q2[8](i,p,12+k|0,t))-1|0){case 0:P2[e+408>>2]=1;break;case 4:break r;default:break n}if(0<=(0|(m=o,l=P2[12+k>>2],_=void 0,d=-1,(0|(_=P2[m+4>>2]))<0||(0|_)<(0|(l=P2[m+8>>2]+l|0))||(P2[m+8>>2]=l,d=0),d)))break i;w=6;break e}r=p0(r,w,g),P2[a>>2]=g+P2[a>>2],P2[e+440>>2]=g+P2[e+440>>2],P2[e+444>>2]=P2[e+444>>2]-g,r=r+g|0}if(!((g=P2[a>>2])>>>0>>0))break}return R2=16+k|0,!g&0!=P2[e+408>>2]}w=5}return R2=16+k|0,w}function X2(e){P2[e+80>>2]=0,P2[e+84>>2]=0,P2[e+64>>2]=1732584193,P2[e+68>>2]=-271733879,P2[e+72>>2]=-1732584194,P2[e+76>>2]=271733878,P2[e+88>>2]=0,P2[e+92>>2]=0}function D0(e,r){var a=0,i=0,t=63&P2[r+80>>2];s0[0|(a=t+r|0)]=128,a=a+1|0,t>>>0<(i=56)?i=55-t|0:(U2(a,63^t),L0(r- -64|0,r),a=r),U2(a,i),a=P2[r+80>>2],P2[r+56>>2]=a<<3,P2[r+60>>2]=P2[r+84>>2]<<3|a>>>29,L0(r- -64|0,r),a=O2[r+76|0]|O2[r+77|0]<<8|(O2[r+78|0]<<16|O2[r+79|0]<<24),t=O2[r+72|0]|O2[r+73|0]<<8|(O2[r+74|0]<<16|O2[r+75|0]<<24),s0[e+8|0]=t,s0[e+9|0]=t>>>8,s0[e+10|0]=t>>>16,s0[e+11|0]=t>>>24,s0[e+12|0]=a,s0[e+13|0]=a>>>8,s0[e+14|0]=a>>>16,s0[e+15|0]=a>>>24,a=O2[r+68|0]|O2[r+69|0]<<8|(O2[r+70|0]<<16|O2[r+71|0]<<24),t=O2[r+64|0]|O2[r+65|0]<<8|(O2[r+66|0]<<16|O2[r+67|0]<<24),s0[0|e]=t,s0[e+1|0]=t>>>8,s0[e+2|0]=t>>>16,s0[e+3|0]=t>>>24,s0[e+4|0]=a,s0[e+5|0]=a>>>8,s0[e+6|0]=a>>>16,s0[e+7|0]=a>>>24,(e=P2[r+88>>2])&&(z2(e),P2[r+88>>2]=0,P2[r+92>>2]=0),U2(r,96)}function L0(e,r){var a,i,t,n,f,o,s,c,u,b,A,k,l=P2[r+16>>2],_=P2[r+32>>2],d=P2[r+48>>2],m=P2[r+36>>2],g=P2[r+52>>2],p=P2[r+4>>2],w=P2[r+20>>2],h=(c=P2[e+4>>2])+K2((((u=P2[r>>2])+(b=P2[e>>2])|0)+((A=P2[e+12>>2])^(A^(k=P2[e+8>>2]))&c)|0)-680876936|0,7)|0,v=P2[r+12>>2],y=P2[r+8>>2],C=K2(((p+A|0)+(h&(c^k)^k)|0)-389564586|0,12)+h|0,E=K2(606105819+((y+k|0)+(C&(h^c)^c)|0)|0,17)+C|0,F=K2(((c+v|0)+(h^E&(h^C))|0)-1044525330|0,22)+E|0;h=K2(((h+l|0)+(C^F&(E^C))|0)-176418897|0,7)+F|0,a=P2[r+28>>2],i=P2[r+24>>2],C=K2(1200080426+((C+w|0)+(E^h&(E^F))|0)|0,12)+h|0,E=K2(((E+i|0)+(F^C&(h^F))|0)-1473231341|0,17)+C|0,F=K2(((F+a|0)+(h^E&(h^C))|0)-45705983|0,22)+E|0,h=K2(1770035416+((h+_|0)+(C^F&(E^C))|0)|0,7)+F|0,t=P2[r+44>>2],n=P2[r+40>>2],C=K2(((C+m|0)+(E^h&(E^F))|0)-1958414417|0,12)+h|0,E=K2(((E+n|0)+(F^C&(h^F))|0)-42063|0,17)+C|0,F=K2(((F+t|0)+(h^E&(h^C))|0)-1990404162|0,22)+E|0,h=K2(1804603682+((h+d|0)+(C^F&(E^C))|0)|0,7)+F|0,f=P2[r+56>>2],o=P2[r+60>>2],s=(r=(C=K2(((C+g|0)+(E^h&(E^F))|0)-40341101|0,12)+h|0)+K2(((E+f|0)+(F^(h^F)&C)|0)-1502002290|0,17)|0)+t|0,E=h+p|0,h=K2(1236535329+((F+o|0)+(h^r&(h^C))|0)|0,22)+r|0,E=K2((E+(r^(h^r)&C)|0)-165796510|0,5)+h|0,r=K2(((C+i|0)+(h^r&(h^E))|0)-1069501632|0,9)+E|0,C=K2(643717713+(s+((E^r)&h^E)|0)|0,14)+r|0,h=K2(((h+u|0)+(r^E&(r^C))|0)-373897302|0,20)+C|0,E=K2(((E+w|0)+(C^r&(h^C))|0)-701558691|0,5)+h|0,r=K2(38016083+((r+n|0)+(h^C&(h^E))|0)|0,9)+E|0,C=K2(((o+C|0)+((E^r)&h^E)|0)-660478335|0,14)+r|0,h=K2(((h+l|0)+(r^E&(r^C))|0)-405537848|0,20)+C|0,E=K2(568446438+((E+m|0)+(C^r&(h^C))|0)|0,5)+h|0,r=K2(((r+f|0)+(h^C&(h^E))|0)-1019803690|0,9)+E|0,C=K2(((C+v|0)+((E^r)&h^E)|0)-187363961|0,14)+r|0,h=K2(1163531501+((h+_|0)+(r^E&(r^C))|0)|0,20)+C|0,E=K2(((E+g|0)+(C^r&(h^C))|0)-1444681467|0,5)+h|0,r=K2(((r+y|0)+(h^C&(h^E))|0)-51403784|0,9)+E|0,C=K2(1735328473+((C+a|0)+((E^r)&h^E)|0)|0,14)+r|0,h=K2(((h+d|0)+(r^(F=r^C)&E)|0)-1926607734|0,20)+C|0,E=K2(((E+w|0)+(h^F)|0)-378558|0,4)+h|0,r=K2(((r+_|0)+(h^C^E)|0)-2022574463|0,11)+E|0,C=K2(1839030562+((C+t|0)+(r^h^E)|0)|0,16)+r|0,h=K2(((h+f|0)+(r^E^C)|0)-35309556|0,23)+C|0,E=K2(((E+p|0)+(r^C^h)|0)-1530992060|0,4)+h|0,r=K2(1272893353+((r+l|0)+(h^C^E)|0)|0,11)+E|0,C=K2(((C+a|0)+(r^h^E)|0)-155497632|0,16)+r|0,h=K2(((h+n|0)+(r^E^C)|0)-1094730640|0,23)+C|0,E=K2(681279174+((E+g|0)+(r^C^h)|0)|0,4)+h|0,r=K2(((r+u|0)+(h^C^E)|0)-358537222|0,11)+E|0,C=K2(((C+v|0)+(r^h^E)|0)-722521979|0,16)+r|0,h=K2(76029189+((h+i|0)+(r^E^C)|0)|0,23)+C|0,F=(E=K2(((E+m|0)+(r^C^h)|0)-640364487|0,4)+h|0)+u|0,u=(r=K2(((r+d|0)+(h^C^E)|0)-421815835|0,11)+E|0)^E,E=K2(530742520+((C+o|0)+(r^h^E)|0)|0,16)+r|0,C=K2(((h+y|0)+(u^E)|0)-995338651|0,23)+E|0,h=K2((F+((C|-1^r)^E)|0)-198630844|0,6)+C|0,F=C+w|0,w=E+f|0,E=K2(1126891415+((r+a|0)+(C^(h|-1^E))|0)|0,10)+h|0,C=K2((w+(h^(E|-1^C))|0)-1416354905|0,15)+E|0,r=K2((F+((C|-1^h)^E)|0)-57434055|0,21)+C|0,F=C+n|0,w=E+v|0,E=K2(1700485571+((h+d|0)+(C^(r|-1^E))|0)|0,6)+r|0,C=K2((w+(r^(E|-1^C))|0)-1894986606|0,10)+E|0,h=K2((F+((C|-1^r)^E)|0)-1051523|0,15)+C|0,F=C+o|0,_=E+_|0,E=K2(((r+p|0)+(C^(h|-1^E))|0)-2054922799|0,21)+h|0,C=K2(1873313359+(_+(h^(E|-1^C))|0)|0,6)+E|0,r=K2((F+((C|-1^h)^E)|0)-30611744|0,10)+C|0,h=K2(((h+i|0)+(C^(r|-1^E))|0)-1560198380|0,15)+r|0,E=K2(1309151649+((E+g|0)+(r^(h|-1^C))|0)|0,21)+h|0,C=K2(((C+l|0)+((E|-1^r)^h)|0)-145523070|0,6)+E|0,P2[e>>2]=C+b,r=K2(((r+t|0)+(E^(C|-1^h))|0)-1120210379|0,10)+C|0,P2[e+12>>2]=r+A,h=K2(718787259+((h+y|0)+(C^(r|-1^E))|0)|0,15)+r|0,P2[e+8>>2]=h+k,s=K2(((E+m|0)+(r^(h|-1^C))|0)-343485551|0,21)+(h+c|0)|0,P2[e+4>>2]=s}function I0(e,r,a,i,t){var n,f=0,o=0,s=0,c=0,u=0,b=0,A=0,k=0;if(b0(t,0,a,0),!T2&&(b0(i,0,s=G2(a,t),0),!T2)){if(o=P2[e+88>>2],n=G2(i,s),S2[e+92>>2]>=n>>>0)f=o;else{e:{if(!(f=h(o,n))){if(z2(o),f=x2(n),P2[e+88>>2]=f)break e;return P2[e+92>>2]=0}P2[e+88>>2]=f}P2[e+92>>2]=n}e:{r:{a:{i:{t:{n:{f:{o:{s:{c:{u:{b:{if((0|(o=G2(t,100)+a|0))<=300){A:switch(o+-101|0){case 3:break t;case 5:break n;case 7:break f;case 2:case 4:case 6:break r;case 0:break a;case 1:break i;default:break A}switch(o+-201|0){case 0:break o;case 1:break s;case 3:break c;case 5:break u;case 7:break b;default:break r}}A:{k:{l:switch(o+-401|0){default:switch(o+-301|0){case 0:break A;case 1:break k;default:break r}case 7:if(!i)break e;for(k=P2[r+28>>2],c=P2[r+24>>2],A=P2[r+20>>2],s=P2[r+16>>2],b=P2[r+12>>2],o=P2[r+8>>2],t=P2[r+4>>2],r=P2[r>>2],a=0;;)if(P2[f>>2]=P2[(u=a<<2)+r>>2],P2[f+4>>2]=P2[t+u>>2],P2[f+8>>2]=P2[o+u>>2],P2[f+12>>2]=P2[b+u>>2],P2[f+16>>2]=P2[s+u>>2],P2[f+20>>2]=P2[u+A>>2],P2[f+24>>2]=P2[c+u>>2],P2[f+28>>2]=P2[u+k>>2],f=f+32|0,(0|i)==(0|(a=a+1|0)))break;break e;case 5:if(!i)break e;for(A=P2[r+20>>2],s=P2[r+16>>2],b=P2[r+12>>2],o=P2[r+8>>2],t=P2[r+4>>2],r=P2[r>>2],a=0;;)if(P2[f>>2]=P2[(c=a<<2)+r>>2],P2[f+4>>2]=P2[t+c>>2],P2[f+8>>2]=P2[o+c>>2],P2[f+12>>2]=P2[c+b>>2],P2[f+16>>2]=P2[s+c>>2],P2[f+20>>2]=P2[c+A>>2],f=f+24|0,(0|i)==(0|(a=a+1|0)))break;break e;case 3:if(!i)break e;for(b=P2[r+12>>2],o=P2[r+8>>2],t=P2[r+4>>2],r=P2[r>>2],a=0;;)if(P2[f>>2]=P2[(s=a<<2)+r>>2],P2[f+4>>2]=P2[t+s>>2],P2[f+8>>2]=P2[o+s>>2],P2[f+12>>2]=P2[s+b>>2],f=f+16|0,(0|i)==(0|(a=a+1|0)))break;break e;case 1:if(!i)break e;for(o=P2[r+4>>2],t=P2[r>>2],r=0;;)if(P2[f>>2]=P2[(a=r<<2)+t>>2],P2[f+4>>2]=P2[a+o>>2],f=f+8|0,(0|i)==(0|(r=r+1|0)))break;break e;case 0:break l;case 2:case 4:case 6:break r}if(!i)break e;for(a=P2[r>>2],r=0;;)if(P2[f>>2]=P2[a+(r<<2)>>2],f=f+4|0,(0|i)==(0|(r=r+1|0)))break;break e}if(!i)break e;for(a=0;;)if(o=P2[(t=a<<2)+P2[r>>2]>>2],s0[0|f]=o,s0[f+2|0]=o>>>16,s0[f+1|0]=o>>>8,t=P2[t+P2[r+4>>2]>>2],s0[f+3|0]=t,s0[f+5|0]=t>>>16,s0[f+4|0]=t>>>8,f=f+6|0,(0|i)==(0|(a=a+1|0)))break;break e}if(!i)break e;for(a=0;;)if(t=P2[P2[r>>2]+(a<<2)>>2],s0[0|f]=t,s0[f+2|0]=t>>>16,s0[f+1|0]=t>>>8,f=f+3|0,(0|i)==(0|(a=a+1|0)))break;break e}if(!i)break e;for(k=P2[r+28>>2],c=P2[r+24>>2],A=P2[r+20>>2],s=P2[r+16>>2],b=P2[r+12>>2],o=P2[r+8>>2],t=P2[r+4>>2],r=P2[r>>2],a=0;;)if(p[f>>1]=P2[(u=a<<2)+r>>2],p[f+2>>1]=P2[t+u>>2],p[f+4>>1]=P2[o+u>>2],p[f+6>>1]=P2[b+u>>2],p[f+8>>1]=P2[s+u>>2],p[f+10>>1]=P2[u+A>>2],p[f+12>>1]=P2[c+u>>2],p[f+14>>1]=P2[u+k>>2],f=f+16|0,(0|i)==(0|(a=a+1|0)))break;break e}if(!i)break e;for(A=P2[r+20>>2],s=P2[r+16>>2],b=P2[r+12>>2],o=P2[r+8>>2],t=P2[r+4>>2],r=P2[r>>2],a=0;;)if(p[f>>1]=P2[(c=a<<2)+r>>2],p[f+2>>1]=P2[t+c>>2],p[f+4>>1]=P2[o+c>>2],p[f+6>>1]=P2[c+b>>2],p[f+8>>1]=P2[s+c>>2],p[f+10>>1]=P2[c+A>>2],f=f+12|0,(0|i)==(0|(a=a+1|0)))break;break e}if(!i)break e;for(b=P2[r+12>>2],o=P2[r+8>>2],t=P2[r+4>>2],r=P2[r>>2],a=0;;)if(p[f>>1]=P2[(s=a<<2)+r>>2],p[f+2>>1]=P2[t+s>>2],p[f+4>>1]=P2[o+s>>2],p[f+6>>1]=P2[s+b>>2],f=f+8|0,(0|i)==(0|(a=a+1|0)))break;break e}if(!i)break e;for(o=P2[r+4>>2],t=P2[r>>2],r=0;;)if(p[f>>1]=P2[(a=r<<2)+t>>2],p[f+2>>1]=P2[a+o>>2],f=f+4|0,(0|i)==(0|(r=r+1|0)))break;break e}if(!i)break e;for(a=P2[r>>2],r=0;;)if(p[f>>1]=P2[a+(r<<2)>>2],f=f+2|0,(0|i)==(0|(r=r+1|0)))break;break e}if(!i)break e;for(t=0;;)if(s0[0|f]=P2[(a=t<<2)+P2[r>>2]>>2],s0[f+1|0]=P2[a+P2[r+4>>2]>>2],s0[f+2|0]=P2[a+P2[r+8>>2]>>2],s0[f+3|0]=P2[a+P2[r+12>>2]>>2],s0[f+4|0]=P2[a+P2[r+16>>2]>>2],s0[f+5|0]=P2[a+P2[r+20>>2]>>2],s0[f+6|0]=P2[a+P2[r+24>>2]>>2],s0[f+7|0]=P2[a+P2[r+28>>2]>>2],f=f+8|0,(0|(t=t+1|0))==(0|i))break;break e}if(!i)break e;for(t=0;;)if(s0[0|f]=P2[(a=t<<2)+P2[r>>2]>>2],s0[f+1|0]=P2[a+P2[r+4>>2]>>2],s0[f+2|0]=P2[a+P2[r+8>>2]>>2],s0[f+3|0]=P2[a+P2[r+12>>2]>>2],s0[f+4|0]=P2[a+P2[r+16>>2]>>2],s0[f+5|0]=P2[a+P2[r+20>>2]>>2],f=f+6|0,(0|(t=t+1|0))==(0|i))break;break e}if(!i)break e;for(t=0;;)if(s0[0|f]=P2[(a=t<<2)+P2[r>>2]>>2],s0[f+1|0]=P2[a+P2[r+4>>2]>>2],s0[f+2|0]=P2[a+P2[r+8>>2]>>2],s0[f+3|0]=P2[a+P2[r+12>>2]>>2],f=f+4|0,(0|(t=t+1|0))==(0|i))break;break e}if(!i)break e;for(a=0;;)if(s0[0|f]=P2[(t=a<<2)+P2[r>>2]>>2],s0[f+1|0]=P2[t+P2[r+4>>2]>>2],f=f+2|0,(0|i)==(0|(a=a+1|0)))break;break e}if(!i)break e;for(a=0;;)if(s0[0|f]=P2[P2[r>>2]+(a<<2)>>2],f=f+1|0,(0|i)==(0|(a=a+1|0)))break;break e}r:switch(t+-1|0){case 3:if(!a|!i)break e;for(o=0;;){for(t=0;;)if(P2[f>>2]=P2[P2[(t<<2)+r>>2]+(o<<2)>>2],f=f+4|0,(0|(t=t+1|0))==(0|a))break;if((0|(o=o+1|0))==(0|i))break}break e;case 2:if(!a|!i)break e;for(;;){for(t=0;;)if(o=P2[P2[(t<<2)+r>>2]+(b<<2)>>2],s0[0|f]=o,s0[f+2|0]=o>>>16,s0[f+1|0]=o>>>8,f=f+3|0,(0|(t=t+1|0))==(0|a))break;if((0|(b=b+1|0))==(0|i))break}break e;case 1:if(!a|!i)break e;for(o=0;;){for(t=0;;)if(p[f>>1]=P2[P2[(t<<2)+r>>2]+(o<<2)>>2],f=f+2|0,(0|(t=t+1|0))==(0|a))break;if((0|(o=o+1|0))==(0|i))break}break e;case 0:break r;default:break e}if(!(!a|!i))for(o=0;;){for(t=0;;)if(s0[0|f]=P2[P2[(t<<2)+r>>2]+(o<<2)>>2],f=f+1|0,(0|(t=t+1|0))==(0|a))break;if((0|(o=o+1|0))==(0|i))break}}if(a=P2[e+80>>2],P2[e+80>>2]=r=a+n|0,i=P2[e+88>>2],r>>>0>>0&&(P2[(r=e+84|0)>>2]=P2[r>>2]+1),r=(e-(t=64-(63&a)|0)|0)+64|0,n>>>0>>0)p0(r,i,n);else{if(p0(r,i,t),L0(a=e- -64|0,e),f=i+t|0,64<=(r=n-t|0)>>>0)for(;;)if(t=O2[f+4|0]|O2[f+5|0]<<8|(O2[f+6|0]<<16|O2[f+7|0]<<24),i=O2[0|f]|O2[f+1|0]<<8|(O2[f+2|0]<<16|O2[f+3|0]<<24),s0[0|e]=i,s0[e+1|0]=i>>>8,s0[e+2|0]=i>>>16,s0[e+3|0]=i>>>24,s0[e+4|0]=t,s0[e+5|0]=t>>>8,s0[e+6|0]=t>>>16,s0[e+7|0]=t>>>24,t=O2[f+60|0]|O2[f+61|0]<<8|(O2[f+62|0]<<16|O2[f+63|0]<<24),i=O2[f+56|0]|O2[f+57|0]<<8|(O2[f+58|0]<<16|O2[f+59|0]<<24),s0[e+56|0]=i,s0[e+57|0]=i>>>8,s0[e+58|0]=i>>>16,s0[e+59|0]=i>>>24,s0[e+60|0]=t,s0[e+61|0]=t>>>8,s0[e+62|0]=t>>>16,s0[e+63|0]=t>>>24,t=O2[f+52|0]|O2[f+53|0]<<8|(O2[f+54|0]<<16|O2[f+55|0]<<24),i=O2[f+48|0]|O2[f+49|0]<<8|(O2[f+50|0]<<16|O2[f+51|0]<<24),s0[e+48|0]=i,s0[e+49|0]=i>>>8,s0[e+50|0]=i>>>16,s0[e+51|0]=i>>>24,s0[e+52|0]=t,s0[e+53|0]=t>>>8,s0[e+54|0]=t>>>16,s0[e+55|0]=t>>>24,t=O2[f+44|0]|O2[f+45|0]<<8|(O2[f+46|0]<<16|O2[f+47|0]<<24),i=O2[f+40|0]|O2[f+41|0]<<8|(O2[f+42|0]<<16|O2[f+43|0]<<24),s0[e+40|0]=i,s0[e+41|0]=i>>>8,s0[e+42|0]=i>>>16,s0[e+43|0]=i>>>24,s0[e+44|0]=t,s0[e+45|0]=t>>>8,s0[e+46|0]=t>>>16,s0[e+47|0]=t>>>24,t=O2[f+36|0]|O2[f+37|0]<<8|(O2[f+38|0]<<16|O2[f+39|0]<<24),i=O2[f+32|0]|O2[f+33|0]<<8|(O2[f+34|0]<<16|O2[f+35|0]<<24),s0[e+32|0]=i,s0[e+33|0]=i>>>8,s0[e+34|0]=i>>>16,s0[e+35|0]=i>>>24,s0[e+36|0]=t,s0[e+37|0]=t>>>8,s0[e+38|0]=t>>>16,s0[e+39|0]=t>>>24,t=O2[f+28|0]|O2[f+29|0]<<8|(O2[f+30|0]<<16|O2[f+31|0]<<24),i=O2[f+24|0]|O2[f+25|0]<<8|(O2[f+26|0]<<16|O2[f+27|0]<<24),s0[e+24|0]=i,s0[e+25|0]=i>>>8,s0[e+26|0]=i>>>16,s0[e+27|0]=i>>>24,s0[e+28|0]=t,s0[e+29|0]=t>>>8,s0[e+30|0]=t>>>16,s0[e+31|0]=t>>>24,t=O2[f+20|0]|O2[f+21|0]<<8|(O2[f+22|0]<<16|O2[f+23|0]<<24),i=O2[f+16|0]|O2[f+17|0]<<8|(O2[f+18|0]<<16|O2[f+19|0]<<24),s0[e+16|0]=i,s0[e+17|0]=i>>>8,s0[e+18|0]=i>>>16,s0[e+19|0]=i>>>24,s0[e+20|0]=t,s0[e+21|0]=t>>>8,s0[e+22|0]=t>>>16,s0[e+23|0]=t>>>24,t=O2[f+12|0]|O2[f+13|0]<<8|(O2[f+14|0]<<16|O2[f+15|0]<<24),i=O2[f+8|0]|O2[f+9|0]<<8|(O2[f+10|0]<<16|O2[f+11|0]<<24),s0[e+8|0]=i,s0[e+9|0]=i>>>8,s0[e+10|0]=i>>>16,s0[e+11|0]=i>>>24,s0[e+12|0]=t,s0[e+13|0]=t>>>8,s0[e+14|0]=t>>>16,s0[e+15|0]=t>>>24,L0(a,e),f=f- -64|0,!(63<(r=r+-64|0)>>>0))break;p0(e,f,r)}f=1}return f}function M0(e){return e&&(P2[2896]=e,1)}function Q0(e){var r,a;return S2[e+20>>2]<=S2[e+28>>2]||(Q2[P2[e+36>>2]](e,0,0),P2[e+20>>2])?((r=P2[e+4>>2])>>>0<(a=P2[e+8>>2])>>>0&&Q2[P2[e+40>>2]](e,r=r-a|0,r>>31,1),P2[e+28>>2]=0,P2[e+16>>2]=0,P2[e+20>>2]=0,P2[e+4>>2]=0,P2[e+8>>2]=0):-1}function P0(e){var r,a,i=0;P2[e+76>>2];(a=1&P2[e>>2])||((i=P2[e+52>>2])&&(P2[i+56>>2]=P2[e+56>>2]),(r=P2[e+56>>2])&&(P2[r+52>>2]=i),P2[3023]==(0|e)&&(P2[3023]=r)),function e(r){var a=0;if(r)return P2[r+76>>2],Q0(r);if(P2[2794]&&(a=e(P2[2794])),r=P2[3023])for(;S2[r+20>>2]>S2[r+28>>2]&&(a=Q0(r)|a),r=P2[r+56>>2];);return a}(e),Q2[P2[e+12>>2]](e),(i=P2[e+96>>2])&&z2(i),a||z2(e)}function O0(e,r,a){var i=0,t=0,n=0;e:if(a){for(;;){if((0|(i=O2[0|e]))!=(0|(t=O2[0|r])))break;if(r=r+1|0,e=e+1|0,!(a=a+-1|0))break e}n=i-t|0}return n}function Z2(e){P2[e+8>>2]=0,P2[e+12>>2]=0,P2[e>>2]=0,P2[e+4>>2]=3,P2[e+56>>2]=0,P2[e+60>>2]=0,P2[e+48>>2]=0,P2[e+52>>2]=0,P2[e+40>>2]=0,P2[e+44>>2]=0,P2[e+32>>2]=0,P2[e+36>>2]=0,P2[e+24>>2]=0,P2[e+28>>2]=0,P2[e+16>>2]=0,P2[e+20>>2]=0}function S0(e){return e=+B(+e),Y2(e)<2147483648?~~e:-2147483648}function N0(e){var r,a,i,t=0,n=0,f=0,o=0,s=0;e:{r:{a:{if(g(+e),t=0|_[1],f=0|_[0],!((0<(0|t)||0<=(0|t)&&!(f>>>0<0))&&1048575<(o=t)>>>0)){if(!(2147483647&t|f))return-1/(e*e);if(-1<(0|t))break a;return(e-e)/0}if(2146435071>>0)break e;if(s=-1023,(t=1072693248)!=(0|o)){t=o;break r}if(f)break r;return 0}g(0x40000000000000*e),t=0|_[1],f=0|_[0],s=-1077}r=((t=t+614242|0)>>>20|0)+s|0,d(0,0|f),d(1,1072079006+(1048575&t)|0),a=.6931471803691238*r,i=1.9082149292705877e-10*r,r=(e=+m()-1)*(.5*e),e=a+(e+(i+(n=e/(e+2))*((e=(n*=n)*n)*(e*(.15313837699209373*e+.22222198432149784)+.3999999999940942)+n*(e*(e*(.14798198605116586*e+.1818357216161805)+.2857142874366239)+.6666666666666735)+r)-r))}return e}function G0(e,r,a,i,t){var n,f,o,s,c,u,b,A=0,k=0,l=0;V2(0);R2=b=R2-16|0;e:if(r){for(A=a+-1|0,a=0;;)if(k=k<(o=+V2(Y2(N2[(a<<2)+e>>2])))?o:k,(0|(a=a+1|0))==(0|r))break;if(l=2,!(k<=0)){if(s=(n=1<>>20&2047))){if(!n)return n=a,a=0==r?0:(r=e(0x10000000000000000*r,a),P2[a>>2]+-64|0),P2[n>>2]=a,r;P2[a>>2]=n+-1022,d(0,0|i),d(1,-2146435073&t|1071644672),r=+m()}return r}(k,12+b|0),a=P2[12+b>>2],P2[12+b>>2]=a+-1,P2[t>>2]=A=A-a|0,(0|(a=-1^(l=-1<>2]=a;else if(!((0|l)<=(0|A))){l=1;break e}if((l=0)<=(0|A)){if(!r)break e;for(a=k=0;;){if(A=S0(k+=+V2(N2[(c=a<<2)+e>>2]*V2(1<>2]=A=(0|A)<(0|n)?(0|A)<(0|f)?f:A:s,(0|(a=a+1|0))==(0|r))break e;k-=0|A,A=P2[t>>2]}}if(r)for(u=V2(1<<(a=0)-A),k=0;;)if(A=S0(k+=+V2(N2[(l=a<<2)+e>>2]/u)),k-=0|(P2[i+l>>2]=A=(0|A)<(0|n)?(0|A)<(0|f)?f:A:s),(0|(a=a+1|0))==(0|r))break;P2[t>>2]=l=0}}else l=2;return R2=16+b|0,l}function V0(e){var r=0,a=0,i=0;e:{r:if(3&(r=e)){if(!O2[0|e])return 0;for(;;){if(!(3&(r=r+1|0)))break r;if(!O2[0|r])break}break e}for(;;)if(r=(a=r)+4|0,(-1^(i=P2[a>>2]))&i+-16843009&-2139062144)break;if(!(255&i))return a-e|0;for(;;)if(i=O2[a+1|0],a=r=a+1|0,!i)break}return r-e|0}function Y0(e,r){return e=((e,r)=>{var a=0,i=0;e:{if(i=255&r){if(3&e)for(;;){if(!(a=O2[0|e])|(0|a)==(255&r))break e;if(!(3&(e=e+1|0)))break}a=P2[e>>2];r:if(!((-1^a)&a+-16843009&-2139062144))for(i=G2(i,16843009);;){if((-1^(a^=i))&a+-16843009&-2139062144)break r;if(a=P2[e+4>>2],e=e+4|0,a+-16843009&(-1^a)&-2139062144)break}for(;;)if(!(i=O2[0|(a=e)])||(e=a+1|0,(0|i)==(255&r)))break;return a}return V0(e)+e|0}return e})(e,r),O2[0|e]==(255&r)?e:0}function q2(e,r,a){var i=0;return 1073741823>>0||(e=x2(e?e<<2:1))&&((i=P2[r>>2])&&z2(i),P2[r>>2]=e,P2[a>>2]=e,i=1),i}function $2(e,r){return r&&e?(b0(r,0,e,0),T2?0:x2(G2(e,r))):x2(1)}function ee(){var e,r,a,i,t=0;if(i=N(1,8)){if(r=N(1,504),P2[i>>2]=r){if(e=N(1,6160),P2[i+4>>2]=e){if(t=N(1,44),P2[e+56>>2]=t){if(P2[e+1128>>2]=16,a=x2(P2[1364]<<1&-16),P2[e+1120>>2]=a)return P2[e+252>>2]=0,P2[e+220>>2]=0,P2[e+224>>2]=0,P2[(t=e+3616|0)>>2]=0,P2[t+4>>2]=0,P2[(t=e+3608|0)>>2]=0,P2[t+4>>2]=0,P2[(t=e+3600|0)>>2]=0,P2[t+4>>2]=0,P2[(t=e+3592|0)>>2]=0,P2[t+4>>2]=0,P2[e+60>>2]=0,P2[e+64>>2]=0,P2[e+68>>2]=0,P2[e+72>>2]=0,P2[e+76>>2]=0,P2[e+80>>2]=0,P2[e+84>>2]=0,P2[e+88>>2]=0,P2[e+92>>2]=0,P2[e+96>>2]=0,P2[e+100>>2]=0,P2[e+104>>2]=0,P2[e+108>>2]=0,P2[e+112>>2]=0,P2[e+116>>2]=0,P2[e+120>>2]=0,n(e+124|0),n(e+136|0),n(e+148|0),n(e+160|0),n(e+172|0),n(e+184|0),n(e+196|0),n(e+208|0),P2[e+48>>2]=0,U2(e+608|(P2[e+52>>2]=0),512),P2[e+1124>>2]=0,P2[e+608>>2]=1,P2[e+32>>2]=0,P2[e+24>>2]=0,P2[e+28>>2]=0,P2[e+16>>2]=0,P2[e+20>>2]=0,P2[e+8>>2]=0,P2[e+12>>2]=0,P2[e>>2]=0,P2[e+4>>2]=0,P2[r+28>>2]=0,F0(r+32|0),P2[r>>2]=9,0|i;T(t)}z2(e)}z2(r)}z2(i)}return 0}function R0(e){var r,a=0;(e|=0)&&(T0(e),a=P2[e+4>>2],(r=P2[a+1120>>2])&&(z2(r),a=P2[e+4>>2]),T(P2[a+56>>2]),t(P2[e+4>>2]+124|0),t(P2[e+4>>2]+136|0),t(P2[e+4>>2]+148|0),t(P2[e+4>>2]+160|0),t(P2[e+4>>2]+172|0),t(P2[e+4>>2]+184|0),t(P2[e+4>>2]+196|0),t(P2[e+4>>2]+208|0),z2(P2[e+4>>2]),z2(P2[e>>2]),z2(e))}function T0(e){var r,a,i,t=0,n=0,n=1;return 9!=P2[P2[(e|=0)>>2]>>2]&&(D0((t=P2[e+4>>2])+3732|0,t+3636|0),z2(P2[P2[e+4>>2]+452>>2]),P2[P2[e+4>>2]+452>>2]=0,t=P2[e+4>>2],P2[t+252>>2]=0,a=P2[t+56>>2],(i=P2[a>>2])&&z2(i),P2[a+36>>2]=0,P2[a+40>>2]=0,P2[a>>2]=0,P2[a+4>>2]=0,P2[a+8>>2]=0,P2[a+12>>2]=0,P2[a+16>>2]=0,n=e+4|(P2[a+20>>2]=0),t=P2[e+4>>2],(i=P2[t+60>>2])&&(z2(i+-16|0),P2[P2[n>>2]+60>>2]=0,t=P2[n>>2]),(i=P2[t+3592>>2])&&(z2(i),P2[P2[n>>2]+92>>2]=0,P2[P2[n>>2]+3592>>2]=0,t=P2[n>>2]),(i=P2[t- -64>>2])&&(z2(i+-16|0),P2[P2[n>>2]- -64>>2]=0,t=P2[n>>2]),(i=P2[t+3596>>2])&&(z2(i),P2[P2[n>>2]+96>>2]=0,P2[P2[n>>2]+3596>>2]=0,t=P2[n>>2]),(i=P2[t+68>>2])&&(z2(i+-16|0),P2[P2[n>>2]+68>>2]=0,t=P2[n>>2]),(i=P2[t+3600>>2])&&(z2(i),P2[P2[n>>2]+100>>2]=0,P2[P2[n>>2]+3600>>2]=0,t=P2[n>>2]),(i=P2[t+72>>2])&&(z2(i+-16|0),P2[P2[n>>2]+72>>2]=0,t=P2[n>>2]),(i=P2[t+3604>>2])&&(z2(i),P2[P2[n>>2]+104>>2]=0,P2[P2[n>>2]+3604>>2]=0,t=P2[n>>2]),(i=P2[t+76>>2])&&(z2(i+-16|0),P2[P2[n>>2]+76>>2]=0,t=P2[n>>2]),(i=P2[t+3608>>2])&&(z2(i),P2[P2[n>>2]+108>>2]=0,P2[P2[n>>2]+3608>>2]=0,t=P2[n>>2]),(i=P2[t+80>>2])&&(z2(i+-16|0),P2[P2[n>>2]+80>>2]=0,t=P2[n>>2]),(i=P2[t+3612>>2])&&(z2(i),P2[P2[n>>2]+112>>2]=0,P2[P2[n>>2]+3612>>2]=0,t=P2[n>>2]),(i=P2[t+84>>2])&&(z2(i+-16|0),P2[P2[n>>2]+84>>2]=0,t=P2[n>>2]),(i=P2[t+3616>>2])&&(z2(i),P2[P2[n>>2]+116>>2]=0,P2[P2[n>>2]+3616>>2]=0,t=P2[n>>2]),(i=P2[t+88>>2])&&(z2(i+-16|0),P2[P2[n>>2]+88>>2]=0,t=P2[n>>2]),(i=P2[t+3620>>2])&&(z2(i),P2[P2[n>>2]+120>>2]=0,P2[P2[n>>2]+3620>>2]=0,t=P2[n>>2]),P2[t+220>>2]=0,P2[t+224>>2]=0,P2[t>>2]&&(t=P2[e>>2]+32|0,(a=t+368|0)&&((r=P2[a>>2])&&z2(r),P2[a>>2]=0,P2[a+4>>2]=0,P2[a+24>>2]=0,P2[a+16>>2]=0,P2[a+20>>2]=0,P2[a+8>>2]=0,P2[a+12>>2]=0),l0(t+8|0),t=P2[e+4>>2]),(i=P2[t+52>>2])&&((0|i)!=P2[1887]&&(P0(i),t=P2[n>>2]),P2[t+52>>2]=0),n=1,P2[t+3624>>2]&&(n=!O0(t+312|0,t+3732|0,16)),P2[t+48>>2]=0,P2[t+3632>>2]=0,U2(t+608|0,512),P2[t+32>>2]=0,P2[t+24>>2]=0,P2[t+28>>2]=0,P2[t+16>>2]=0,P2[t+20>>2]=0,P2[t+8>>2]=0,P2[t+12>>2]=0,P2[t>>2]=0,P2[t+4>>2]=0,t=P2[e+4>>2],P2[t+1124>>2]=0,P2[t+608>>2]=1,t=P2[e>>2],P2[t+28>>2]=0,F0(t+32|0),P2[P2[e>>2]>>2]=9),0|n}function re(e,r,a,i,t,n,f,o,s,c){return 0|U0(e|=0,r|=0,a|=0,i|=0,t|=0,n|=0,f|=0,o|=0,s|=0,c|=0,0)}function U0(e,r,a,i,t,n,f,o,s,c,u){var b,A,k,l=0,l=5;e:{if(b=P2[e>>2],9==P2[b>>2]&&(l=2,!(!r|!f|!s||a&&!i|!t|!n))){if(l=P2[e+4>>2],P2[l>>2]=u){if(!E0(b+32|0))break e;l=P2[e+4>>2]}if(Z2(l+3524|0),u=P2[e+4>>2],P2[u+44>>2]=5,P2[u+40>>2]=6,P2[u+36>>2]=5,b=P2[u+56>>2],A=e,P2[b+8>>2]=0,P2[b+12>>2]=0,P2[b+4>>2]=2048,P2[b+16>>2]=0,P2[b+20>>2]=0,k=x2(8192),!((P2[b>>2]=k)&&(P2[b+40>>2]=A,P2[b+36>>2]=7)))return P2[P2[e>>2]>>2]=8,3;u=P2[e+4>>2],P2[u+48>>2]=c,P2[u+32>>2]=s,P2[u+28>>2]=o,P2[u+24>>2]=f,P2[u+20>>2]=n,P2[u+16>>2]=t,P2[u+12>>2]=i,P2[u+8>>2]=a,P2[u+4>>2]=r,P2[u+3520>>2]=0,P2[u+248>>2]=0,P2[u+240>>2]=0,P2[u+244>>2]=0,P2[u+228>>2]=0,P2[u+232>>2]=0,P2[u+3624>>2]=P2[P2[e>>2]+28>>2],P2[u+3628>>2]=1,P2[u+3632>>2]=0,l=x0(e)?0:3}return l}return P2[P2[e>>2]+4>>2]=4}function x0(e){var r,a=0,i=0,a=P2[(e|=0)+4>>2];e:if(9!=P2[P2[e>>2]>>2]||P2[a+3628>>2]){if(P2[a+3624>>2]=0,P2[a+240>>2]=0,P2[a+244>>2]=0,P2[a>>2]&&(C0((a=P2[e>>2]+32|0)+8|0),y0(a+368|0),P2[a+408>>2]=0,P2[a+412>>2]=0,a=P2[e+4>>2]),a=P2[a+56>>2],P2[a+8>>2]=0,P2[a+12>>2]=0,P2[a+16>>2]=0,P2[a+20>>2]=0,i=P2[e>>2],!(a=1))return P2[i>>2]=8,0;if(P2[i>>2]=2,a=P2[e+4>>2],P2[a>>2]&&(C0((r=i+32|0)+8|0),y0(r+368|0),P2[r+408>>2]=0,P2[r+412>>2]=0,P2[r>>2]&&(P2[r+404>>2]=1),a=P2[e+4>>2]),P2[a+3628>>2])P2[a+3628>>2]=0;else{if(i=0,P2[a+52>>2]==P2[1887])break e;if(r=P2[a+8>>2]){if(1==(0|Q2[r](e,0,0,P2[a+48>>2])))break e;a=P2[e+4>>2]}}P2[P2[e>>2]>>2]=0,P2[a+248>>2]=0,z2(P2[a+452>>2]),P2[P2[e+4>>2]+452>>2]=0,a=P2[e+4>>2],P2[a+252>>2]=0,P2[a+3624>>2]=P2[P2[e>>2]+28>>2],P2[a+228>>2]=0,P2[a+232>>2]=0,X2(a+3636|0),e=P2[e+4>>2],P2[e+6152>>2]=0,P2[e+6136>>2]=0,P2[e+6140>>2]=0,i=1}return 0|i}function z0(e){return P2[P2[(e|=0)>>2]>>2]}function j0(e){e|=0;var r,a=0,i=0;R2=r=R2-16|0,a=1;e:{for(;;){r:{a:switch(P2[P2[e>>2]>>2]){case 0:if(H0(e))continue;a=0;break r;case 1:i=0!=(0|K0(e));break e;case 2:if(W0(e))continue;break r;case 4:case 7:break r;case 3:break a;default:break e}if(J0(e,12+r|0)){if(!P2[12+r>>2])continue}else a=0}break}i=a}return R2=16+r|0,0|i}function H0(e){var r,a=0,i=0,t=0,n=0,f=0,o=0;R2=r=R2-16|0,n=1;e:{for(;;){a=0;r:{for(;;){if(f=P2[e+4>>2],P2[f+3520>>2])t=O2[f+3590|0],P2[8+r>>2]=t,P2[f+3520>>2]=0;else{if(!E(P2[f+56>>2],8+r|0,8)){i=0;break e}t=P2[8+r>>2]}if(O2[i+5409|0]==(0|t)){i=i+1|0,a=1;break r}if(3==((i=0)|a))break e;if(O2[a+7552|0]!=(0|t))break;if(3==(0|(a=a+1|0))){if(!(E(P2[P2[e+4>>2]+56>>2],12+r|0,24)&&E(P2[P2[e+4>>2]+56>>2],12+r|0,8)&&(t=P2[12+r>>2],E(P2[P2[e+4>>2]+56>>2],12+r|0,8))&&(f=P2[12+r>>2],E(P2[P2[e+4>>2]+56>>2],12+r|0,8))&&(o=P2[12+r>>2],E(P2[P2[e+4>>2]+56>>2],12+r|0,8))))break e;if(!Z(P2[P2[e+4>>2]+56>>2],127&P2[12+r>>2]|o<<7&16256|(127&f|t<<7&16256)<<14))break e}}if(255==(0|t)){if(s0[P2[e+4>>2]+3588|0]=255,!E(P2[P2[e+4>>2]+56>>2],8+r|0,8))break e;if(255==(0|(a=P2[8+r>>2])))a=P2[e+4>>2],P2[a+3520>>2]=1,s0[a+3590|0]=255;else if(248==(-2&a)){s0[P2[e+4>>2]+3589|0]=a,P2[P2[e>>2]>>2]=3,i=1;break e}}a=0,n&&(n=P2[e+4>>2],a=0,P2[n+3632>>2]||(Q2[P2[n+32>>2]](e,0,P2[n+48>>2]),a=0))}if(n=a,!(i>>>0<4))break}P2[P2[e>>2]>>2]=i=1}return R2=16+r|0,i}function K0(e){var r,a,i,t,n,f,o=0,s=0,c=0,u=0,b=0,A=0,k=0,l=0,_=0,d=0,m=0,g=0,p=0,w=0;R2=f=R2-192|0;e:{r:if(E(P2[P2[e+4>>2]+56>>2],184+f|0,P2[1391])){if(r=P2[184+f>>2],!E(P2[P2[(u=e+4|0)>>2]+56>>2],180+f|0,P2[1392]))break e;if(!E(P2[P2[u>>2]+56>>2],176+f|0,P2[1393]))break e;A=0!=(0|r);a:{i:{t:{n:{f:switch(0|(s=P2[180+f>>2])){case 3:break n;case 0:break f;default:break t}if(c=P2[176+f>>2],o=P2[u>>2],P2[o+256>>2]=s=0,P2[o+264>>2]=c,P2[o+260>>2]=A,!E(b=P2[o+56>>2],f,o=P2[1356]))break e;if(P2[P2[u>>2]+272>>2]=P2[f>>2],b=P2[1357],!E(P2[P2[u>>2]+56>>2],f,b))break e;if(P2[P2[u>>2]+276>>2]=P2[f>>2],A=P2[1358],!E(P2[P2[u>>2]+56>>2],f,A))break e;if(P2[P2[u>>2]+280>>2]=P2[f>>2],k=P2[1359],!E(P2[P2[u>>2]+56>>2],f,k))break e;if(P2[P2[u>>2]+284>>2]=P2[f>>2],l=P2[1360],!E(P2[P2[u>>2]+56>>2],f,l))break e;if(P2[P2[u>>2]+288>>2]=P2[f>>2],_=P2[1361],!E(P2[P2[u>>2]+56>>2],f,_))break e;if(P2[P2[u>>2]+292>>2]=P2[f>>2]+1,d=P2[1362],!E(P2[P2[u>>2]+56>>2],f,d))break e;if(P2[P2[u>>2]+296>>2]=P2[f>>2]+1,m=P2[u>>2],!W(g=P2[m+56>>2],p=m+304|0,m=P2[1363]))break e;if(g=P2[u>>2],!q(P2[g+56>>2],g+312|0,16))break e;if(!Z(P2[P2[u>>2]+56>>2],c-(128+(m+(d+(_+(l+(k+(A+(o+b|0)|0)|0)|0)|0)|0)|0)>>>3|0)|0))break r;if(o=P2[u>>2],P2[o+248>>2]=1,O0(o+312|0,7555,16)||(P2[o+3624>>2]=0),P2[o+3632>>2]|!P2[o+608>>2])break i;if(!(s=P2[o+28>>2]))break i;Q2[s](e,o+256|0,P2[o+48>>2]);break i}o=P2[u>>2],P2[o+252>>2]=0,b=P2[176+f>>2],P2[o+448>>2]=(b>>>0)/18,P2[o+440>>2]=b,P2[o+436>>2]=A,P2[o+432>>2]=3,o=P2[u>>2],s=P2[o+452>>2];n:{if(c=P2[o+448>>2]){if(b0(c,0,24,0),!T2){if(o=h(s,G2(c,24))){P2[P2[u>>2]+452>>2]=o;break n}z2(s),o=P2[u>>2]}P2[o+452>>2]=0;break a}if(o=h(s,0),!(P2[P2[u>>2]+452>>2]=o))break a}if(s=P2[u>>2],o=0,P2[s+448>>2]){for(A=P2[1367],k=P2[1366],l=P2[1365],c=0;;){if(!W(P2[s+56>>2],f,l))break r;if(s=P2[4+f>>2],o=G2(c,24),_=P2[u>>2],d=o+P2[_+452>>2]|0,P2[d>>2]=P2[f>>2],P2[d+4>>2]=s,!W(P2[_+56>>2],f,k))break r;if(s=P2[4+f>>2],_=P2[u>>2],d=o+P2[_+452>>2]|0,P2[d+8>>2]=P2[f>>2],P2[d+12>>2]=s,!E(P2[_+56>>2],188+f|0,A))break r;if(s=P2[u>>2],P2[16+(o+P2[s+452>>2]|0)>>2]=P2[188+f>>2],!((c=c+1|0)>>>0<(o=P2[s+448>>2])>>>0))break}o=G2(o,-18)}if(o=o+b|0){if(!Z(P2[s+56>>2],o))break r;s=P2[u>>2]}if(P2[s+252>>2]=1,P2[s+3632>>2]|!P2[s+620>>2])break i;if(!(o=P2[s+28>>2]))break i;Q2[o](e,s+432|0,P2[s+48>>2]);break i}c=P2[u>>2],k=P2[608+(c+(s<<2)|0)>>2],b=P2[176+f>>2],o=U2(f,176),P2[o+8>>2]=b,P2[o>>2]=s,P2[o+4>>2]=A,l=!k;t:if(2==(0|s)){if(A=P2[1364]>>>3|0,!q(P2[c+56>>2],_=o+16|0,A))break r;if(b>>>0>>0){P2[P2[e>>2]>>2]=8,s=0;break e}if(b=b-A|0,c=P2[u>>2],d=P2[c+1124>>2]){for(m=P2[c+1120>>2],s=0;;){if(O0(m+G2(s,A)|0,_,A)){if((0|d)!=(0|(s=s+1|0)))continue;break t}break}l=0!=(0|k)}}if(l){if(Z(P2[c+56>>2],b))break i;break r}t:{n:{f:{o:{s:{c:{u:switch(P2[o+180>>2]){case 1:if(Z(P2[c+56>>2],b))break s;A=0;break t;case 2:if(!b)break c;if(s=x2(b),!(P2[o+20>>2]=s)){P2[P2[e>>2]>>2]=8,A=0;break t}if(q(P2[c+56>>2],s,b))break s;A=0;break t;case 4:b:if(!(b>>>0<8)){if(!J(P2[c+56>>2],o+16|(A=0)))break t;if(b=b+-8|0,s=P2[o+16>>2]){if(b>>>0>>0){P2[o+16>>2]=0,P2[o+20>>2]=0;break b}A:{if(-1==(0|s))P2[o+20>>2]=0;else if(c=x2(s+1|0),P2[o+20>>2]=c)break A;P2[P2[e>>2]>>2]=8;break t}if(!q(P2[P2[u>>2]+56>>2],c,s))break t;b=b-s|0,s0[P2[o+20>>2]+P2[o+16>>2]|0]=0}else P2[o+20>>2]=0;if(!J(P2[P2[u>>2]+56>>2],o+24|0))break t;if(100001<=(s=P2[o+24>>2])>>>0){P2[o+24>>2]=0;break t}if(s){if(c=$2(s,8),!(P2[o+28>>2]=c))break f;if(P2[o+24>>2]){P2[c>>2]=0,s=P2[c+4>>2]=0;A:if(!(b>>>0<4))for(;;){if(!J(P2[P2[u>>2]+56>>2],c))break n;if(b=b+-4|0,k=P2[o+28>>2],A=P2[(c=k+(l=s<<3)|0)>>2]){if(b>>>0>>0)break A;k:{if(-1==(0|A))P2[4+(k+(s<<3)|0)>>2]=0;else if(k=x2(A+1|0),P2[c+4>>2]=k)break k;P2[P2[e>>2]>>2]=8;break n}if(b=b-A|0,U2(k,P2[c>>2]),A=q(P2[P2[u>>2]+56>>2],P2[c+4>>2],P2[c>>2]),k=l+P2[o+28>>2]|0,c=P2[k+4>>2],!A){z2(c),P2[4+(P2[o+28>>2]+(s<<3)|0)>>2]=0;break A}s0[c+P2[k>>2]|0]=0}else P2[c+4>>2]=0;if((s=s+1|0)>>>0>=S2[o+24>>2])break b;if(c=P2[o+28>>2]+(s<<3)|0,P2[c>>2]=0,!(4<=b>>>(P2[c+4>>2]=0)))break}P2[o+24>>2]=s}}}if(!b)break s;if(P2[o+24>>2]||(z2(P2[(s=o+28|0)>>2]),P2[s>>2]=0),Z(P2[P2[u>>2]+56>>2],b))break s;A=0;break t;case 5:if(s=U2(o+16|(A=0),160),!q(P2[c+56>>2],s,P2[1378]>>>3|0))break t;if(!W(P2[P2[u>>2]+56>>2],o+152|0,P2[1379]))break t;if(!E(P2[P2[u>>2]+56>>2],o+188|0,P2[1380]))break t;if(P2[o+160>>2]=0!=P2[o+188>>2],!X(P2[P2[u>>2]+56>>2],P2[1381]))break t;if(!E(P2[P2[u>>2]+56>>2],o+188|0,P2[1382]))break t;if(s=P2[o+188>>2],!(P2[o+164>>2]=s))break s;if(s=N(s,32),!(P2[o+168>>2]=s))break o;if(l=P2[1371],!W(P2[P2[u>>2]+56>>2],s,l))break t;for(_=P2[1373]>>>3|0,d=P2[1370],m=P2[1369],k=P2[1368],g=P2[1377],a=P2[1376],i=P2[1375],t=P2[1374],n=P2[1372],b=0;;){if(!E(P2[P2[u>>2]+56>>2],o+188|0,n))break t;if(s0[(s=(b<<5)+s|0)+8|0]=P2[o+188>>2],!q(P2[P2[u>>2]+56>>2],s+9|0,_))break t;if(!E(P2[P2[u>>2]+56>>2],o+188|0,t))break t;if(s0[s+22|0]=254&O2[s+22|0]|1&s0[o+188|0],!E(P2[P2[u>>2]+56>>2],o+188|0,i))break t;if(s0[0|(c=s+22|0)]=O2[o+188|0]<<1&2|253&O2[0|c],!X(P2[P2[u>>2]+56>>2],a))break t;if(!E(P2[P2[u>>2]+56>>2],o+188|0,g))break t;c=P2[o+188>>2],s0[s+23|0]=c;b:if(c&=255){if(c=N(c,16),!(P2[s+24>>2]=c)){P2[P2[e>>2]>>2]=8;break t}if(O2[0|(p=s+23|0)]){if(!W(P2[P2[u>>2]+56>>2],c,k))break t;for(w=s+24|0,s=0;;){if(!E(P2[P2[u>>2]+56>>2],o+188|0,m))break t;if(s0[8+((s<<4)+c|0)|0]=P2[o+188>>2],!X(P2[P2[u>>2]+56>>2],d))break t;if((s=s+1|0)>>>0>=O2[0|p])break b;if(c=P2[w>>2],!W(P2[P2[u>>2]+56>>2],c+(s<<4)|0,k))break}break t}}if((b=b+1|0)>>>0>=S2[o+164>>2])break s;if(s=P2[o+168>>2],!W(P2[P2[u>>2]+56>>2],s+(b<<5)|0,l))break}break t;case 6:b:if(E(P2[c+56>>2],o+188|0,P2[1383])&&(P2[o+16>>2]=P2[o+188>>2],E(P2[P2[u>>2]+56>>2],o+188|0,P2[1384]))){A:{if(-1==(0|(s=P2[o+188>>2])))P2[o+20>>2]=0;else if(c=x2(s+1|0),P2[o+20>>2]=c)break A;P2[P2[e>>2]>>2]=8,A=0;break t}if(s){if(!q(P2[P2[u>>2]+56>>2],c,s))break b;c=P2[o+20>>2],s=P2[o+188>>2]}else s=0;if(s0[s+c|0]=0,E(P2[P2[u>>2]+56>>2],o+188|0,P2[1385])){A:{if(-1==(0|(s=P2[o+188>>2])))P2[o+24>>2]=0;else if(c=x2(s+1|0),P2[o+24>>2]=c)break A;P2[P2[e>>2]>>2]=8,A=0;break t}if(s){if(!q(P2[P2[u>>2]+56>>2],c,s))break b;c=P2[o+24>>2],s=P2[o+188>>2]}else s=0;if(s0[s+c|0]=0,E(P2[P2[u>>2]+56>>2],o+28|0,P2[1386])&&E(P2[P2[u>>2]+56>>2],o+32|0,P2[1387])&&E(P2[P2[u>>2]+56>>2],o+36|0,P2[1388])&&E(P2[P2[u>>2]+56>>2],o+40|0,P2[1389])&&E(P2[P2[u>>2]+56>>2],o+44|0,P2[1390])){if(c=x2((s=P2[o+44>>2])||1),!(P2[o+48>>2]=c)){P2[P2[e>>2]>>2]=8,A=0;break t}if(!s)break s;if(q(P2[P2[u>>2]+56>>2],c,s))break s}}}A=0;break t;case 0:case 3:break s;default:break u}u:{if(b){if(s=x2(b),P2[o+16>>2]=s)break u;P2[P2[e>>2]>>2]=8,A=0;break t}P2[o+16>>2]=0;break s}if(q(P2[c+56>>2],s,b))break s;A=0;break t}P2[o+20>>2]=0}if(A=1,s=P2[u>>2],P2[s+3632>>2])break t;if(!(c=P2[s+28>>2]))break t;Q2[c](e,o,P2[s+48>>2]);break t}P2[P2[e>>2]>>2]=8;break t}P2[o+24>>2]=0,P2[P2[e>>2]>>2]=8;break t}P2[o+24>>2]=s,A=0}t:{n:switch(P2[o+180>>2]+-1|0){case 1:if(!(o=P2[o+20>>2]))break t;z2(o);break t;case 3:if((s=P2[o+20>>2])&&z2(s),c=P2[o+24>>2])for(s=0;;)if((b=P2[4+(P2[o+28>>2]+(s<<3)|0)>>2])&&(z2(b),c=P2[o+24>>2]),!((s=s+1|0)>>>0>>0))break;if(!(o=P2[o+28>>2]))break t;z2(o);break t;case 4:if(c=P2[o+164>>2])for(s=0;;)if((b=P2[24+(P2[o+168>>2]+(s<<5)|0)>>2])&&(z2(b),c=P2[o+164>>2]),!((s=s+1|0)>>>0>>0))break;if(!(o=P2[o+168>>2]))break t;z2(o);break t;case 5:if((s=P2[o+20>>2])&&z2(s),(s=P2[o+24>>2])&&z2(s),!(o=P2[o+48>>2]))break t;z2(o);break t;case 0:break t;default:break n}(o=P2[o+16>>2])&&z2(o)}if(!A)break r}if(s=1,!r)break e;c=P2[u>>2],!P2[c>>2]&&(b=P2[c+12>>2])&&!Q2[b](e,o=c+6136|0,P2[c+48>>2])&&z(P2[P2[u>>2]+56>>2])?(c=P2[o>>2],u=P2[P2[u>>2]+56>>2],u=((P2[u+8>>2]-P2[u+16>>2]<<5)+(P2[u+12>>2]<<3)|0)-P2[u+20>>2]>>>3|0,b=P2[o+4>>2]-(c>>>0>>0)|0,P2[o>>2]=c-u,P2[o+4>>2]=b):(o=P2[u>>2],P2[o+6136>>2]=0,P2[o+6140>>2]=0),P2[P2[e>>2]>>2]=2;break e}P2[P2[e>>2]>>2]=8}s=0}return R2=192+f|0,s}function W0(e){var r,a,i=0,t=0,n=0;R2=a=R2-16|0;e:{r:if(t=P2[e+4>>2],P2[t+248>>2]&&(i=n=P2[t+308>>2])|(r=P2[t+304>>2])&&!((0|i)==(0|(n=P2[t+244>>2]))&S2[t+240>>2]>>0|n>>>0>>0))P2[P2[e>>2]>>2]=4;else{if(!z(P2[t+56>>2])&&!E(t=P2[P2[e+4>>2]+56>>2],12+a|0,j(t))){i=0;break e}for(t=0;;){if(n=P2[e+4>>2],P2[n+3520>>2])i=O2[n+3590|0],P2[12+a>>2]=i,P2[n+3520>>2]=0;else{if(!E(P2[n+56>>2],12+a|(i=0),8))break e;i=P2[12+a>>2]}if(255==(0|i)){if(s0[P2[e+4>>2]+3588|0]=255,!E(P2[P2[e+4>>2]+56>>2],12+a|(i=0),8))break e;if(255==(0|(i=P2[12+a>>2])))i=P2[e+4>>2],P2[i+3520>>2]=1,s0[i+3590|0]=255;else if(248==(-2&i)){s0[P2[e+4>>2]+3589|0]=i,P2[P2[e>>2]>>2]=3;break r}}i=t,t=1,i||(i=P2[e+4>>2],P2[i+3632>>2])||Q2[P2[i+32>>2]](e,0,P2[i+48>>2])}}i=1}return R2=16+a|0,i}function J0(e,r){var a,i,t,n,f,o,s,c=0,u=0,b=0,A=0,k=0,l=0,_=0,d=0,m=0,g=0,p=0,w=0,h=0,v=0,y=0;R2=s=R2+-64|0,P2[r>>2]=0,c=P2[e+4>>2],b=C[1280+(O2[c+3588|0]<<1)>>1],A=P2[c+56>>2],P2[A+24>>2]=C[1280+((O2[c+3589|0]^b>>>8)<<1)>>1]^b<<8&65280,c=P2[A+20>>2],P2[A+28>>2]=P2[A+16>>2],P2[A+32>>2]=c,A=P2[e+4>>2],s0[32+s|0]=O2[A+3588|0],c=O2[A+3589|0],P2[12+s>>2]=2,s0[33+s|0]=c;e:if(E(P2[A+56>>2],28+s|0,8)){b=e+4|0;r:{a:{i:{if(255!=(0|(A=P2[28+s>>2]))){if(s0[34+s|0]=A,P2[12+s>>2]=3,!E(P2[P2[b>>2]+56>>2],28+s|0,8))break a;if(255!=(0|(A=P2[28+s>>2]))){l=c>>>1&1,c=P2[12+s>>2],s0[c+(32+s|0)|0]=A,P2[12+s>>2]=c+(A=1),c=O2[34+s|0];t:{n:{f:{o:switch((P2[28+s>>2]=u=c>>>4|0)-1|0){case 7:case 8:case 9:case 10:case 11:case 12:case 13:case 14:P2[P2[b>>2]+1136>>2]=256<>2]+1136>>2]=576<>2]+1136>>2]=192}u=0}A=l}t:{n:{f:switch((P2[28+s>>2]=k=15&c)-1|0){default:if(k=0,l=P2[b>>2],P2[l+248>>2])break n;A=1;break t;case 0:P2[P2[b>>2]+1140>>2]=88200,k=0;break t;case 1:P2[P2[b>>2]+1140>>2]=176400,k=0;break t;case 2:P2[P2[b>>2]+1140>>2]=192e3,k=0;break t;case 3:P2[P2[b>>2]+1140>>2]=8e3,k=0;break t;case 4:P2[P2[b>>2]+1140>>2]=16e3,k=0;break t;case 5:P2[P2[b>>2]+1140>>2]=22050,k=0;break t;case 6:P2[P2[b>>2]+1140>>2]=24e3,k=0;break t;case 7:P2[P2[b>>2]+1140>>2]=32e3,k=0;break t;case 8:P2[P2[b>>2]+1140>>2]=44100,k=0;break t;case 9:P2[P2[b>>2]+1140>>2]=48e3,k=0;break t;case 10:P2[P2[b>>2]+1140>>2]=96e3,k=0;break t;case 11:case 12:case 13:break t;case 14:break f}A=P2[b>>2],P2[A+3632>>2]||Q2[P2[A+32>>2]](e,1,P2[A+48>>2]),c=P2[e>>2],P2[c>>2]=2;break i}P2[l+1140>>2]=P2[l+288>>2]}d=O2[35+s|0];t:{n:if(8&(P2[28+s>>2]=_=d>>>4|0)){c=P2[b>>2],P2[c+1144>>2]=2;f:switch(7&_){case l=1:l=2;break n;case 0:break n;case 2:break f;default:break t}l=3}else c=P2[b>>2],P2[c+1144>>2]=_+1,l=0;P2[c+1148>>2]=l,l=A}t:{n:{f:switch((P2[28+s>>2]=_=d>>>1&7)-(A=1)|0){default:if(!P2[c+248>>2])break t;P2[c+1152>>2]=P2[c+296>>2];break n;case 0:P2[c+1152>>2]=8;break n;case 1:P2[c+1152>>2]=12;break n;case 3:P2[c+1152>>2]=16;break n;case 4:P2[c+1152>>2]=20;break n;case 2:case 6:break t;case 5:break f}P2[c+1152>>2]=24}A=l}if(!(!P2[c+248>>2]|P2[c+272>>2]==P2[c+276>>2])||1&s0[33+s|0]){if(!((e,r,a,i)=>{var t,n,f,o=0,s=0,c=0;t:if(E(e,12+(R2=f=R2-16|0)|0,8)){o=P2[12+f>>2],a&&(c=P2[i>>2],P2[i>>2]=c+1,s0[a+c|0]=o);n:{f:{o:{s:{if(128&o){if(!(!(192&o)|32&o)){o&=31,s=1;break s}if(!(!(224&o)|16&o)){o&=15,s=2;break s}if(!(!(240&o)|8&o)){o&=7,s=3;break s}if(!(!(248&o)|4&o)){o&=3,s=4;break s}if(!(!(252&o)|2&o)){o&=1,s=5;break s}if(!(!(254&o)|(s=1)&o)){s=6,o=0;break s}P2[r>>2]=-1,P2[r+4>>2]=-1;break t}c=0;break o}if(c=0,!a)for(;;){if(!E(e,12+f|0,8)){s=0;break t}if(128!=(192&(a=P2[12+f>>2])))break f;if(c=c<<6|o>>>26,o=(a&=63)|o<<6,!(s=s+-1|0))break o}for(;;){if(!E(e,12+f|0,8)){s=0;break t}if(t=P2[12+f>>2],n=P2[i>>2],P2[i>>2]=n+1,128!=(192&(s0[a+n|0]=t)))break f;if(c=c<<6|o>>>26,o=63&t|o<<6,!(s=s+-1|0))break}}P2[r>>2]=o,P2[r+4>>2]=c;break n}P2[r>>2]=-1,P2[r+4>>2]=-1}s=1}return R2=16+f|0,s})(P2[c+56>>2],16+s|0,32+s|0,12+s|0))break a;if(c=l=P2[20+s>>2],-1==(0|(_=P2[16+s>>2]))&-1==(0|c)){l=O2[31+(P2[12+s>>2]+s|0)|0],A=P2[b>>2],P2[A+3520>>2]=1,s0[A+3590|0]=l,P2[A+3632>>2]||Q2[P2[A+32>>2]](e,1,P2[A+48>>2]),c=P2[e>>2],P2[c>>2]=2;break i}l=P2[b>>2],P2[(m=l+1160|0)>>2]=_,P2[m+4>>2]=c,P2[l+1156>>2]=1}else{if(!((e,r,a,i)=>{var t,n,f=0,o=0,s=0,c=0;t:if(E(e,12+(R2=n=R2-16|0)|0,8)){f=P2[12+n>>2],a&&(o=P2[i>>2],P2[i>>2]=o+1,s0[a+o|0]=f);n:{f:{o:{s:if(128&f){if(!(192&f)|32&f)if(!(224&f)|16&f)if(!(240&f)|8&f){if(!(248&f)||(s=3,(o=4)&f)){if(!(252&f)|2&f)break o;s=1,o=5}}else s=7,o=3;else s=15,o=2;else s=31,o=1;if(f&=s,!a)for(;;){if(!E(e,12+n|0,8))break t;if(128!=(192&(a=P2[12+n>>2])))break f;if(f=63&a|f<<6,!(o=o+-1|0))break s}for(;;){if(!E(e,12+n|0,8))break t;if(s=P2[12+n>>2],t=P2[i>>2],P2[i>>2]=t+1,128!=(192&(s0[a+t|0]=s)))break f;if(f=63&s|f<<6,!(o=o+-1|0))break}}P2[r>>2]=f;break n}P2[r>>2]=-1;break n}P2[r>>2]=-1}c=1}return R2=16+n|0,c})(P2[c+56>>2],28+s|0,32+s|0,12+s|0))break a;if(-1==(0|(l=P2[28+s>>2]))){l=O2[31+(P2[12+s>>2]+s|0)|0],A=P2[b>>2],P2[A+3520>>2]=1,s0[A+3590|0]=l,P2[A+3632>>2]||Q2[P2[A+32>>2]](e,1,P2[A+48>>2]),c=P2[e>>2],P2[c>>2]=2;break i}c=P2[b>>2],P2[c+1160>>2]=l,P2[c+1156>>2]=0}if(c=P2[b>>2],u){if(!E(P2[c+56>>2],28+s|0,8))break a;if(c=P2[12+s>>2],l=P2[28+s>>2],s0[c+(32+s|0)|0]=l,P2[12+s>>2]=c+1,7==(0|u)){if(!E(P2[P2[b>>2]+56>>2],8+s|0,8))break a;l=P2[12+s>>2],c=P2[8+s>>2],s0[l+(32+s|0)|0]=c,P2[12+s>>2]=l+1,l=c|P2[28+s>>2]<<8,P2[28+s>>2]=l}c=P2[b>>2],P2[c+1136>>2]=l+1}if(k){if(!E(P2[c+56>>2],28+s|0,8))break a;if(l=P2[12+s>>2],c=P2[28+s>>2],s0[l+(32+s|0)|0]=c,P2[12+s>>2]=l+1,12!=(0|k)){if(!E(P2[P2[b>>2]+56>>2],8+s|0,8))break a;l=P2[12+s>>2],c=P2[8+s>>2],s0[l+(32+s|0)|0]=c,P2[12+s>>2]=l+1,u=c|P2[28+s>>2]<<8,P2[28+s>>2]=u,13!=(0|k)&&(u=G2(u,10))}else u=G2(c,1e3);c=P2[b>>2],P2[c+1140>>2]=u}if(!E(P2[c+56>>2],28+s|0,8))break a;if(l=O2[28+s|0],u=V(32+s|0,P2[12+s>>2]),c=P2[b>>2],(0|u)!=(0|l)){P2[c+3632>>2]||Q2[P2[c+32>>2]](e,1,P2[c+48>>2]),c=P2[e>>2],P2[c>>2]=2;break i}P2[c+232>>2]=0;t:{if(!P2[c+1156>>2])if(l=P2[(u=c+1160|0)>>2],P2[28+s>>2]=l,P2[c+1156>>2]=1,k=P2[c+228>>2])v=u,y=b0(k,0,l,0),P2[v>>2]=y,P2[u+4>>2]=T2;else if(P2[c+248>>2]){if((0|(u=P2[c+272>>2]))!=P2[c+276>>2])break t;v=c=c+1160|0,y=b0(u,0,l,0),P2[v>>2]=y,P2[c+4>>2]=T2,l=P2[b>>2],P2[l+232>>2]=P2[l+276>>2]}else l?(v=u=c+1160|0,y=b0(P2[c+1136>>2],0,l,0),P2[v>>2]=y,P2[u+4>>2]=T2):(P2[(l=c+1160|0)>>2]=0,P2[l+4>>2]=0,l=P2[b>>2],P2[l+232>>2]=P2[l+1136>>2]);if(!(A|1&d)){c=P2[e>>2];break i}c=P2[b>>2]}P2[c+3632>>2]?P2[c+6152>>2]=P2[c+6152>>2]+1:Q2[P2[c+32>>2]](e,3,P2[c+48>>2]),c=P2[e>>2],P2[c>>2]=2;break i}}A=P2[b>>2],P2[A+3520>>2]=1,s0[A+3590|0]=255,P2[A+3632>>2]||Q2[P2[A+32>>2]](e,1,P2[A+48>>2]),c=P2[e>>2],P2[c>>2]=2}if(l=1,2==P2[c>>2])break e;if(c=P2[b>>2],A=P2[c+1144>>2],k=P2[c+1136>>2],!(S2[c+224>>2]>=A>>>0&&S2[c+220>>2]>=k>>>0)){(u=P2[c+60>>2])&&(z2(u+-16|0),P2[P2[b>>2]+60>>2]=0,c=P2[b>>2]),(u=P2[c+3592>>2])&&(z2(u),P2[P2[b>>2]+92>>2]=0,P2[P2[b>>2]+3592>>2]=0,c=P2[b>>2]),(u=P2[c- -64>>2])&&(z2(u+-16|0),P2[P2[b>>2]- -64>>2]=0,c=P2[b>>2]),(u=P2[c+3596>>2])&&(z2(u),P2[P2[b>>2]+96>>2]=0,P2[P2[b>>2]+3596>>2]=0,c=P2[b>>2]),(u=P2[c+68>>2])&&(z2(u+-16|0),P2[P2[b>>2]+68>>2]=0,c=P2[b>>2]),(u=P2[c+3600>>2])&&(z2(u),P2[P2[b>>2]+100>>2]=0,P2[P2[b>>2]+3600>>2]=0,c=P2[b>>2]),(u=P2[c+72>>2])&&(z2(u+-16|0),P2[P2[b>>2]+72>>2]=0,c=P2[b>>2]),(u=P2[c+3604>>2])&&(z2(u),P2[P2[b>>2]+104>>2]=0,P2[P2[b>>2]+3604>>2]=0,c=P2[b>>2]),(u=P2[c+76>>2])&&(z2(u+-16|0),P2[P2[b>>2]+76>>2]=0,c=P2[b>>2]),(u=P2[c+3608>>2])&&(z2(u),P2[P2[b>>2]+108>>2]=0,P2[P2[b>>2]+3608>>2]=0,c=P2[b>>2]),(u=P2[c+80>>2])&&(z2(u+-16|0),P2[P2[b>>2]+80>>2]=0,c=P2[b>>2]),(u=P2[c+3612>>2])&&(z2(u),P2[P2[b>>2]+112>>2]=0,P2[P2[b>>2]+3612>>2]=0,c=P2[b>>2]),(u=P2[c+84>>2])&&(z2(u+-16|0),P2[P2[b>>2]+84>>2]=0,c=P2[b>>2]),(u=P2[c+3616>>2])&&(z2(u),P2[P2[b>>2]+116>>2]=0,P2[P2[b>>2]+3616>>2]=0,c=P2[b>>2]),(u=P2[c+88>>2])&&(z2(u+-16|0),P2[P2[b>>2]+88>>2]=0,c=P2[b>>2]),(c=P2[c+3620>>2])&&(z2(c),P2[P2[b>>2]+120>>2]=0,P2[P2[b>>2]+3620>>2]=0);i:if(A){if(4294967291>>0)break r;if((1073741823&(c=k+4|0))!=(0|c))break r;for(_=c<<2,u=0;;){if(!(c=x2(_)))break r;if(P2[c>>2]=0,P2[c+4>>2]=0,P2[c+8>>2]=0,P2[c+12>>2]=0,P2[60+((d=u<<2)+P2[b>>2]|0)>>2]=c+16,!q2(k,(c=d+P2[b>>2]|0)+3592|0,c+92|0))break;if((0|A)==(0|(u=u+1|0)))break i}P2[P2[e>>2]>>2]=8;break a}c=P2[b>>2],P2[c+224>>2]=A,P2[c+220>>2]=k,A=P2[c+1144>>2]}i:{if(A)for(f=-1<<(i=P2[1412])^-1,t=P2[1406],n=P2[1405],o=P2[1413],A=0;;){u=P2[c+1152>>2];t:{n:switch(P2[c+1148>>2]+-1|0){case 0:u=(1==(0|A))+u|0;break t;case 1:u=!A+u|0;break t;case 2:break n;default:break t}u=(1==(0|A))+u|0}if(!E(P2[c+56>>2],28+s|0,8))break a;if(c=P2[28+s>>2],P2[28+s>>2]=254&c,p=1&c){if(!$(P2[P2[b>>2]+56>>2],32+s|0))break a;if(c=P2[b>>2],k=P2[32+s>>2]+1|0,u>>>0<=(P2[1464+(c+G2(A,292)|0)>>2]=k)>>>0)break a;u=u-k|0}else c=P2[b>>2],P2[1464+(c+G2(A,292)|0)>>2]=0;t:if(128&(k=P2[28+s>>2]))P2[c+3632>>2]||Q2[P2[c+32>>2]](e,0,P2[c+48>>2]),P2[P2[e>>2]>>2]=2;else{n:{f:{o:switch(0|k){case 0:if(k=P2[60+((A<<2)+c|0)>>2],_=G2(A,292)+c|0,P2[_+1176>>2]=0,!K(P2[c+56>>2],32+s|0,u))break a;if(P2[_+1180>>2]=P2[32+s>>2],c=0,u=P2[b>>2],!P2[u+1136>>2])break f;for(;;)if(P2[k+(c<<2)>>2]=P2[32+s>>2],!((c=c+1|0)>>>0>2]))break;break f;case 2:if(k=(c+1136|0)+G2(A,292)|0,m=P2[92+((d=A<<2)+c|0)>>2],P2[(_=k+44|0)>>2]=m,P2[k+40>>2]=1,k=0,P2[c+1136>>2]){for(;;){if(!K(P2[c+56>>2],32+s|0,u))break a;if(P2[m+(k<<2)>>2]=P2[32+s>>2],c=P2[b>>2],!((k=k+1|0)>>>0<(g=P2[c+1136>>2])>>>0))break}k=g<<2}p0(P2[60+(c+d|0)>>2],P2[_>>2],k);break f;default:break o}if(k>>>0<=15){P2[c+3632>>2]?P2[c+6152>>2]=P2[c+6152>>2]+1:Q2[P2[c+32>>2]](e,3,P2[c+48>>2]),P2[P2[e>>2]>>2]=2;break t}if(k>>>0<=24){if(_=G2(A,292)+c|0,P2[_+1176>>2]=2,g=P2[92+((m=A<<2)+c|0)>>2],P2[_+1192>>2]=d=k>>>1&7,P2[_+1212>>2]=g,k=P2[c+56>>2],d)for(g=_+1196|0,c=0;;){if(!K(k,32+s|0,u))break a;if(P2[g+(c<<2)>>2]=P2[32+s>>2],k=P2[P2[b>>2]+56>>2],(0|d)==(0|(c=c+1|0)))break}if(!E(k,16+s|0,n))break a;u=P2[16+s>>2],P2[(k=_+1180|0)>>2]=u,c=P2[b>>2];o:{s:{if(u>>>0<=1){if(!E(P2[c+56>>2],16+s|0,t))break a;if(c=P2[b>>2],u=P2[16+s>>2],P2[c+1136>>2]>>>u>>>0>=d>>>0)break s;P2[c+3632>>2]||Q2[P2[c+32>>2]](e,0,P2[c+48>>2]),P2[P2[e>>2]>>2]=2;break o}P2[c+3632>>2]?P2[c+6152>>2]=P2[c+6152>>2]+1:Q2[P2[c+32>>2]](e,3,P2[c+48>>2]),P2[P2[e>>2]>>2]=2;break o}if(P2[_+1184>>2]=u,c=G2(A,12),P2[_+1188>>2]=124+(c+P2[b>>2]|0),(k=P2[k>>2])>>>0<2&&!X0(e,d,w=u,124+(c+(u=P2[e+4>>2])|0)|0,P2[92+(u+m|0)>>2],1==(0|k)))break a;p0(P2[60+(m+P2[b>>2]|0)>>2],_+1196|0,c=d<<2),u=P2[b>>2],((e,r,a,i)=>{var t=0,n=0,f=0,o=0,s=0;s:{c:{u:switch(0|a){case 4:if((0|r)<1)break c;for(n=P2[i+-12>>2],f=P2[i+-4>>2],a=0;;)if(t=P2[(o=(s=a<<2)+i|0)+-8>>2],f=((P2[e+s>>2]+G2(t,-6)|0)-P2[o+-16>>2]|0)+(n+f<<2)|0,P2[o>>2]=f,n=t,(0|(a=a+1|0))==(0|r))break;break c;case 3:if((0|r)<1)break c;for(t=P2[i+-12>>2],n=P2[i+-4>>2],a=0;;)if(s=P2[e+(f=a<<2)>>2]+t|0,t=P2[(o=f+i|0)+-8>>2],n=s+G2(n-t|0,3)|0,P2[o>>2]=n,(0|(a=a+1|0))==(0|r))break;break c;case 2:if((0|r)<1)break c;for(t=P2[i+-4>>2],a=0;;)if(t=(P2[e+(n=a<<2)>>2]+(t<<1)|0)-P2[(f=n+i|0)+-8>>2]|0,P2[f>>2]=t,(0|(a=a+1|0))==(0|r))break;break c;case 0:break s;case 1:break u;default:break c}if(!((0|r)<1))for(t=P2[i+-4>>2],a=0;;)if(t=P2[(n=a<<2)+e>>2]+t|0,P2[i+n>>2]=t,(0|(a=a+1|0))==(0|r))break}return}p0(i,e,r<<2)})(P2[(k=u+m|0)+92>>2],P2[u+1136>>2]-d|0,d,c+P2[k+60>>2]|0)}if(2==P2[P2[e>>2]>>2])break t;if(p)break n;break t}if(k>>>0<=63){P2[c+3632>>2]?P2[c+6152>>2]=P2[c+6152>>2]+1:Q2[P2[c+32>>2]](e,3,P2[c+48>>2]),P2[P2[e>>2]>>2]=2;break t}for(_=G2(A,292)+c|0,P2[_+1176>>2]=3,h=P2[92+((m=A<<2)+c|0)>>2],P2[_+1192>>2]=d=(g=k>>>1&31)+1|0,P2[_+1460>>2]=h,k=P2[c+56>>2],c=0;;){if(!K(k,32+s|0,u))break a;if(P2[1332+(_+(c<<2)|0)>>2]=P2[32+s>>2],h=(0|c)!=(0|g),k=P2[P2[b>>2]+56>>2],c=c+1|0,!h)break}if(!E(k,16+s|0,i))break a;o:if((0|(c=P2[16+s>>2]))==(0|f))c=P2[b>>2],P2[c+3632>>2]||Q2[P2[c+32>>2]](e,0,P2[c+48>>2]),P2[P2[e>>2]>>2]=2;else{if(P2[(a=_+1196|0)>>2]=c+1,!K(P2[P2[b>>2]+56>>2],32+s|0,o))break a;if((0|(c=P2[32+s>>2]))<=-1)c=P2[b>>2],P2[c+3632>>2]||Q2[P2[c+32>>2]](e,0,P2[c+48>>2]),P2[P2[e>>2]>>2]=2;else{for(P2[(h=_+1200|0)>>2]=c,k=P2[P2[b>>2]+56>>2],c=0;;){if(!K(k,32+s|0,P2[a>>2]))break a;if(P2[1204+(_+(c<<2)|0)>>2]=P2[32+s>>2],w=(0|c)!=(0|g),k=P2[P2[b>>2]+56>>2],c=c+1|0,!w)break}if(!E(k,16+s|0,n))break a;k=P2[16+s>>2],P2[(w=_+1180|0)>>2]=k,c=P2[b>>2];s:{if(k>>>0<=1){if(!E(P2[c+56>>2],16+s|0,t))break a;if(c=P2[b>>2],k=P2[16+s>>2],P2[c+1136>>2]>>>k>>>0>g>>>0)break s;P2[c+3632>>2]||Q2[P2[c+32>>2]](e,0,P2[c+48>>2]),P2[P2[e>>2]>>2]=2;break o}P2[c+3632>>2]?P2[c+6152>>2]=P2[c+6152>>2]+1:Q2[P2[c+32>>2]](e,3,P2[c+48>>2]),P2[P2[e>>2]>>2]=2;break o}if(P2[_+1184>>2]=k,c=G2(A,12),P2[_+1188>>2]=124+(c+P2[b>>2]|0),(g=P2[w>>2])>>>0<2&&!X0(e,d,w=k,124+(c+(k=P2[e+4>>2])|0)|0,P2[92+(k+m|0)>>2],1==(0|g)))break a;p0(P2[60+(P2[b>>2]+m|0)>>2],_+1332|0,k=d<<2);s:{if((g=P2[a>>2])+((31^g0(d))+u|0)>>>0<=32){if(c=P2[b>>2],16>>0|16>>0)break s;Q2[P2[c+44>>2]](P2[(u=c+m|0)+92>>2],P2[c+1136>>2]-d|0,_+1204|0,d,P2[h>>2],k+P2[u+60>>2]|0);break o}c=P2[b>>2],Q2[P2[c+40>>2]](P2[(u=c+m|0)+92>>2],P2[c+1136>>2]-d|0,_+1204|0,d,P2[h>>2],k+P2[u+60>>2]|0);break o}Q2[P2[c+36>>2]](P2[(u=c+m|0)+92>>2],P2[c+1136>>2]-d|0,_+1204|0,d,P2[h>>2],k+P2[u+60>>2]|0)}}if(!p|2==P2[P2[e>>2]>>2])break t;break n}if(!p)break t}if(u=P2[b>>2],c=P2[1464+(u+G2(A,292)|0)>>2],P2[28+s>>2]=c,P2[u+1136>>2]&&(k=P2[60+(u+(A<<2)|0)>>2],P2[k>>2]=P2[k>>2]<>2]<2)))for(;;)if(P2[(_=k+(c<<2)|0)>>2]=P2[_>>2]<>2],!((c=c+1|0)>>>0>2]))break}if(2==P2[P2[e>>2]>>2])break i;if(c=P2[b>>2],!((A=A+1|0)>>>0>2]))break}if(!z(P2[c+56>>2])){if(P2[32+s>>2]=0,!E(A=P2[P2[b>>2]+56>>2],32+s|0,j(A)))break a;P2[32+s>>2]&&(A=P2[b>>2],P2[A+3632>>2]||Q2[P2[A+32>>2]](e,0,P2[A+48>>2]),P2[P2[e>>2]>>2]=2)}if(2==P2[P2[e>>2]>>2])break e;if(A=(e=>{var r,a,i=0,t=0,n=0,f=0,o=0;if((a=P2[e+16>>2])>>>0<=(t=P2[e+28>>2])>>>0)f=t;else if(i=P2[e+32>>2]){if(P2[e+28>>2]=f=t+1|0,n=P2[e+24>>2],i>>>0<=31){for(t=P2[P2[e>>2]+(t<<2)>>2];;)if(n=C[1280+((t>>>24-i&255^n>>>8)<<1)>>1]^n<<8&65280,r=i>>>0<24,i=o=i+8|0,!r)break;P2[e+32>>2]=o}P2[e+32>>2]=0,P2[e+24>>2]=n}else f=t;if(i=Y(P2[e>>2]+(f<<2)|0,a-f|0,C[e+24>>1]),P2[e+28>>2]=0,P2[e+24>>2]=i,(t=P2[e+20>>2])&&!(t>>>0<=(n=P2[e+32>>2])>>>0)){for(f=P2[P2[e>>2]+(P2[e+16>>2]<<2)>>2];;)if(i=C[1280+((f>>>24-n&255^i>>>8)<<1)>>1]^i<<8&65280,!((n=n+8|0)>>>0>>0))break;P2[e+32>>2]=n,P2[e+24>>2]=i}return i})(P2[P2[b>>2]+56>>2]),!E(P2[P2[b>>2]+56>>2],16+s|(l=0),P2[1404]))break e;t:if((0|A)==P2[16+s>>2]){n:{f:{o:switch(A=P2[b>>2],P2[A+1148>>2]+-1|0){case 2:break n;case 0:break f;case 1:break o;default:break t}if(!P2[A+1136>>2])break t;for(c=P2[A- -64>>2],k=P2[A+60>>2],u=0;;)if(P2[(d=(_=u<<2)+k|0)>>2]=P2[d>>2]+P2[c+_>>2],!((u=u+1|0)>>>0>2]))break;break t}if(!P2[A+1136>>2])break t;for(c=P2[A- -64>>2],k=P2[A+60>>2],u=0;;)if(P2[(d=(_=u<<2)+c|0)>>2]=P2[k+_>>2]-P2[d>>2],!((u=u+1|0)>>>0>2]))break;break t}if(P2[A+1136>>2])for(d=P2[A- -64>>2],m=P2[A+60>>2],u=0;;)if(c=(k=u<<2)+m|0,_=1&(k=P2[(p=k+d|0)>>2])|P2[c>>2]<<1,P2[c>>2]=k+_>>1,P2[p>>2]=_-k>>1,!((u=u+1|0)>>>0>2]))break}else if(A=P2[b>>2],P2[A+3632>>2]||Q2[P2[A+32>>2]](e,2,P2[A+48>>2]),c=P2[b>>2],P2[c+1144>>2])for(u=0;;)if(U2(P2[60+((u<<2)+c|0)>>2],P2[c+1136>>2]<<2),c=P2[b>>2],!((u=u+1|0)>>>0>2]))break;P2[r>>2]=1,c=P2[b>>2],(r=P2[c+232>>2])&&(P2[c+228>>2]=r),r=P2[e>>2],k=P2[c+1144>>2],P2[r+8>>2]=k,P2[r+12>>2]=P2[c+1148>>2],p=P2[c+1152>>2],P2[r+16>>2]=p,P2[r+20>>2]=P2[c+1140>>2],A=P2[c+1136>>2],P2[r+24>>2]=A,_=P2[(r=c+1160|0)>>2],r=u=P2[r+4>>2],(g=A+_|0)>>>0>>0&&(r=r+1|0),P2[c+240>>2]=g,P2[c+244>>2]=r,d=c+60|0,m=c+1136|0;t:{n:{if(P2[c+3632>>2]){if(P2[c+6156>>2]=1,p=P2[c+6144>>2],A=P2[c+6148>>2],p0(c+3752|0,m,2384),(0|u)==(0|A)&p>>>0<_>>>0|A>>>0>>0|(0|r)==(0|A)&g>>>0<=p>>>0|r>>>0>>0)break t;if(r=P2[b>>2],b=A=p-_|(P2[r+3632>>2]=u=0)){if(k)for(;;)if(P2[(_=u<<2)+(32+s|0)>>2]=P2[60+(c+_|0)>>2]+(b<<2),(0|k)==(0|(u=u+1|0)))break;P2[r+3752>>2]=P2[r+3752>>2]-b,r=P2[(u=b=c=r+3776|0)+4>>2],(c=A+P2[c>>2]|0)>>>0>>0&&(r=r+1|0),P2[u>>2]=c,P2[b+4>>2]=r,r=P2[e+4>>2],r=0|Q2[P2[r+24>>2]](e,r+3752|0,32+s|0,P2[r+48>>2])}else r=0|Q2[P2[r+24>>2]](e,m,d,P2[r+48>>2])}else{if(P2[c+248>>2]){if(P2[c+3624>>2]){if(!I0(c+3636|0,d,k,A,p+7>>>3|0))break n;c=P2[b>>2]}}else P2[c+3624>>2]=0;r=0|Q2[P2[c+24>>2]](e,m,d,P2[c+48>>2])}if(!r)break t}P2[P2[e>>2]>>2]=7;break e}P2[P2[e>>2]>>2]=2}l=1;break e}l=0;break e}P2[P2[e>>2]>>2]=8,l=0}return R2=s+64|0,l}function X0(e,r,a,i,t,n){var f,o,s,c=0,u=0,b=0,A=0,k=0;R2=s=R2-16|0,c=P2[P2[e+4>>2]+1136>>2],f=P2[(n?5644:5640)>>2],o=P2[(n?5632:5628)>>2];e:{r:{if(k0(i,6>>0?a:6)){if(u=a?c>>>a|0:c-r|0,k=P2[1409],!a)break r;for(n=0;;){if(!E(P2[P2[e+4>>2]+56>>2],12+s|0,o)){c=0;break e}if(P2[(b=A<<2)+P2[i>>2]>>2]=P2[12+s>>2],S2[12+s>>2]>>0){if(P2[b+P2[i+4>>2]>>2]=c=0,!e0(P2[P2[e+4>>2]+56>>2],(n<<2)+t|0,b=u-(A?0:r)|0,P2[12+s>>2]))break e;n=n+b|0}else{if(!E(P2[P2[e+4>>2]+56>>2],12+s|0,k)){c=0;break e}if(P2[b+P2[i+4>>2]>>2]=P2[12+s>>2],!(u>>>0<=(c=A?0:r)>>>0))for(;;){if(!K(P2[P2[e+4>>2]+56>>2],8+s|0,P2[12+s>>2])){c=0;break e}if(P2[(n<<2)+t>>2]=P2[8+s>>2],n=n+1|0,(0|u)==(0|(c=c+1|0)))break}}if((A=A+(c=1)|0)>>>a)break}break e}P2[P2[e>>2]>>2]=8,c=0;break e}if(E(P2[P2[e+4>>2]+56>>2],12+s|(c=0),o)){if(P2[P2[i>>2]>>2]=P2[12+s>>2],S2[12+s>>2]>=f>>>0){if(!E(P2[P2[e+4>>2]+56>>2],12+s|0,k))break e;if(P2[P2[i+4>>2]>>2]=P2[12+s>>2],u)for(n=0;;){if(!K(P2[P2[e+4>>2]+56>>2],8+s|0,P2[12+s>>2])){c=0;break e}if(P2[(n<<2)+t>>2]=P2[8+s>>2],n=n+1|0,(0|u)==(0|(c=c+1|0)))break}}else if(P2[P2[i+4>>2]>>2]=0,!e0(P2[P2[e+4>>2]+56>>2],t,u,P2[12+s>>2]))break e;c=1}}return R2=16+s|0,c}function Z0(e){P2[e+12>>2]=0,P2[e+16>>2]=0}function q0(e,r){var a,i=0;return $0(e,12+(R2=e=R2-16|0)|(i=0),8+e|0)&&(r=r,a=((e,r)=>{var a,i=0;if(7>>0)for(;;)if(a=i,i=O2[0|e]|O2[e+1|0]<<8,i=C[1280+(O2[e+7|0]<<1)>>1]^(C[512+(1280+(O2[e+6|0]<<1)|0)>>1]^(C[2304+(O2[e+5|0]<<1)>>1]^(C[2816+(O2[e+4|0]<<1)>>1]^(C[3328+(O2[e+3|0]<<1)>>1]^(C[3840+(O2[e+2|0]<<1)>>1]^(C[4352+((255&(i=a^(i<<8&16711680|i<<24)>>>16))<<1)>>1]^C[4864+(i>>>7&510)>>1])))))),e=e+8|0,!(7<(r=r+-8|0)>>>0))break;if(r)for(;;)if(i=C[1280+((O2[0|e]^(65280&i)>>>8)<<1)>>1]^i<<8,e=e+1|0,!(r=r+-1|0))break;return 65535&i})(P2[12+e>>2],P2[8+e>>2]),p[r>>1]=a,i=1),R2=16+e|0,i}function $0(e,r,a){var i=0,t=0,n=0,f=0,n=P2[e+16>>2];e:if(!(7&n)){if(n){if((0|(f=P2[e+12>>2]))==P2[e+8>>2]&&!((i=(t=n+63>>>5|0)+f|0)>>>0<=f>>>0)){n=P2[e>>2],i;r:{if(i=i+((i=1023&t)?1024-i|0:0)|(f=0)){if((0|i)!=(1073741823&i))break e;if(t=h(n,i<<2))break r;return z2(n),0}if(!(t=h(n,0)))break e}P2[e+8>>2]=i,P2[e>>2]=t,f=P2[e+12>>2],n=P2[e+16>>2]}t=P2[e>>2],i=P2[e+4>>2]<<32-n,P2[t+(f<<2)>>2]=i<<24|i<<8&16711680|i>>>8&65280|i>>>24,i=P2[e+16>>2]>>>3|0}else t=P2[e>>2],i=0;P2[r>>2]=t,P2[a>>2]=i+(P2[e+12>>2]<<2),f=1}return f}function e2(e,r){var a=0,i=0,t=0,n=0;e:{r:if(r){if(a=P2[e+8>>2],!((i=P2[e+12>>2])+r>>>0>>0||(t=i+(31+(P2[e+16>>2]+r|0)>>>5|0)|0)>>>0<=a>>>0)){n=P2[e>>2];a:{if(a=t+((a=t-a&1023)?1024-a|0:0)|(i=0)){if((0|a)!=(1073741823&a))break e;if(t=h(n,a<<2))break a;return z2(n),0}if(!(t=h(n,0)))break e}P2[e+8>>2]=a,P2[e>>2]=t}if(a=P2[e+16>>2]){if(t=a,P2[e+16>>2]=n=t+(i=(a=32-a|0)>>>0>>0?a:r)|0,a=P2[e+4>>2]<>2]=a,32!=(0|n))break r;n=P2[e+12>>2],P2[e+12>>2]=n+1,P2[P2[e>>2]+(n<<2)>>2]=a<<8&16711680|a<<24|a>>>8&65280|a>>>24,r=r-i|(P2[e+16>>2]=0)}if(32<=r>>>0)for(a=P2[e>>2];;)if(i=P2[e+12>>2],P2[e+12>>2]=i+1,!(31<(r=r+-32|(P2[a+(i<<2)>>2]=0))>>>0))break;r&&(P2[e+16>>2]=r,P2[e+4>>2]=0)}i=1}return i}function j2(e,r,a){var i=0;return i=a>>>0<=31&&(i=0,r>>>a)?i:l(e,r,a)}function l(e,r,a){var i,t,n=0,f=0,o=0;e:if(!(!e|32>>0)&&(i=P2[e>>2])&&(o=1,a)){if(t=P2[e+8>>2],(n=P2[e+12>>2])+a>>>0>>0)n=i;else if((f=n+(31+(P2[e+16>>2]+a|0)>>>5|0)|0)>>>0<=t>>>0)n=i;else{r:{if(f=f+((n=f-t&1023)?1024-n|0:0)|(o=0)){if((0|f)!=(1073741823&f))break e;if(n=h(i,f<<2))break r;return z2(i),0}if(!(n=h(i,0)))break e}P2[e+8>>2]=f,P2[e>>2]=n}if(a>>>0<(f=32-(i=P2[e+16>>2])|0)>>>0)return P2[e+16>>2]=a+i,P2[e+4>>2]=P2[e+4>>2]<>2]=i=a-f|0,a=P2[e+12>>2],P2[e+12>>2]=a+1,n=(a<<2)+n|0,a=P2[e+4>>2]<>>i,P2[n>>2]=a<<24|a<<8&16711680|a>>>8&65280|a>>>24,P2[e+4>>2]=r,1;e=P2[(a=e)+12>>2],P2[a+12>>2]=e+(o=1),P2[(e<<2)+n>>2]=r<<8&16711680|r<<24|r>>>8&65280|r>>>24}return o}function r2(e,r,a){return l(e,(a>>>0<32?-1<>>0){if(!(a>>>(i=i+-32|0)|0&&i>>>0<=31)&&l(e,a,i))return 0!=(0|l(e,r,32))}else 32!=(0|i)&&r>>>i||(t=l(e,r,i));return t}function i2(e,r){var a=0;return a=l(e,255&r,8)&&l(e,r>>>8&255,8)&&l(e,r>>>16&255,8)?0!=(0|l(e,r>>>24|0,8)):a}function t2(e,r,a){var i,t=0,n=0,f=P2[e+8>>2],t=P2[e+12>>2];e:{if(!(1+(t+(a>>>2|0)|0)>>>0>>0||(n=t+(31+(P2[e+16>>2]+(a<<3)|0)>>>5|0)|0)>>>0<=f>>>0)){i=P2[e>>2];r:{if(f=n+((f=n-f&1023)?1024-f|0:0)|(t=0)){if((0|f)!=(1073741823&f))break e;if(n=h(i,f<<2))break r;return void z2(i)}if(!(n=h(i,0)))break e}P2[e+8>>2]=f,P2[e>>2]=n}if(t=1,a){t=0;r:{for(;;){if(!l(e,O2[r+t|0],8))break r;if((0|(t=t+1|0))==(0|a))break}return 1}t=0}}return t}function n2(e,r){return r>>>0<=31?l(e,1,r+1|0):e2(e,r)&&0!=(0|l(e,1,1))}function f2(e,r,a,i){var t,n,f,o,s=0,c=0,u=0,b=0,A=0,s=1;e:if(a){for(n=i+1|0,f=-1<>>31-i|0;;){if(s=n+(u=(t=(u=P2[r>>2])<<1^u>>31)>>>i|0)|0,!(c=P2[e+16>>2])||31<(b=s+c|0)>>>0){if(A=P2[e+8>>2],!(1+((b=P2[e+12>>2])+(c+u|0)|0)>>>0>>0||(s=b+(31+(s+c|0)>>>5|0)|0)>>>0<=A>>>0)){b=P2[e>>2];r:{if(c=s+((c=s-A&1023)?1024-c|0:0)|0){if(((s=0)|c)!=(1073741823&c))break e;if(A=h(b,c<<2))break r;return void z2(b)}if(!(A=h(b,s=0)))break e}P2[e+8>>2]=c,P2[e>>2]=A}r:if(u){if(s=P2[e+16>>2]){if(c=P2[e+4>>2],u>>>0<(b=32-s|0)>>>0){P2[e+16>>2]=s+u,P2[e+4>>2]=c<>2]=s=c<>2],P2[e+12>>2]=c+1,P2[P2[e>>2]+(c<<2)>>2]=s<<8&16711680|s<<24|s>>>8&65280|s>>>24,u=u-b|(P2[e+16>>2]=0)}if(32<=u>>>0)for(s=P2[e>>2];;)if(c=P2[e+12>>2],P2[e+12>>2]=c+1,!(31<(u=u+-32|(P2[s+(c<<2)>>2]=0))>>>0))break;u&&(P2[e+16>>2]=u,P2[e+4>>2]=0)}u=(t|f)&o,s=P2[e+4>>2],n>>>0<(c=32-(b=P2[e+16>>2])|0)>>>0?(P2[e+16>>2]=b+n,P2[e+4>>2]=u|s<>2]=b=n-c|0,t=P2[e+12>>2],P2[e+12>>2]=t+1,P2[P2[e>>2]+(t<<2)>>2]=(s=s<>>b)<<24|s<<8&16711680|s>>>8&65280|s>>>24,P2[e+4>>2]=u)}else P2[e+16>>2]=b,P2[e+4>>2]=(t|f)&o|P2[e+4>>2]<>2]=0,P2[e+4>>2]=0}function s2(e,r,a,i,t,n,f,o,s){var c,u,b,A,k=0,l=0;R2=A=R2-96|0;e:{r:{if(P2[e+384>>2]){P2[72+A>>2]=0,P2[76+A>>2]=0,P2[(l=c=80+A|0)>>2]=0,P2[l+4>>2]=0,P2[88+A>>2]=0,P2[92+A>>2]=0,P2[64+A>>2]=0,P2[68+A>>2]=0,k=P2[e+396>>2],(b=(l=i)+(u=P2[e+392>>2])|0)>>>0>>0&&(k=k+1|0),P2[c>>2]=b,P2[4+c>>2]=k;a:{if(P2[e+388>>2]){if(38!=(0|a))break a;s0[0|A]=O2[7536],a=P2[2721],a=O2[0|a]|O2[a+1|0]<<8|(O2[a+2|0]<<16|O2[a+3|0]<<24),s0[5+A|0]=1,s0[6+A|0]=0,s0[1+A|0]=a,s0[2+A|0]=a>>>8,s0[3+A|0]=a>>>16,s0[4+A|0]=a>>>24,k=P2[e+4>>2],a=O2[5409]|O2[5410]<<8|(O2[5411]<<16|O2[5412]<<24),s0[9+A|0]=a,s0[10+A|0]=a>>>8,s0[11+A|0]=a>>>16,s0[12+A|0]=a>>>24,s0[8+A|0]=k,s0[7+A|0]=k>>>8,a=O2[r+34|0]|O2[r+35|0]<<8|(O2[r+36|0]<<16|O2[r+37|0]<<24),k=O2[r+30|0]|O2[r+31|0]<<8|(O2[r+32|0]<<16|O2[r+33|0]<<24),s0[43+A|0]=k,s0[44+A|0]=k>>>8,s0[45+A|0]=k>>>16,s0[46+A|0]=k>>>24,s0[47+A|0]=a,s0[48+A|0]=a>>>8,s0[49+A|0]=a>>>16,s0[50+A|0]=a>>>24,a=O2[r+28|0]|O2[r+29|0]<<8|(O2[r+30|0]<<16|O2[r+31|0]<<24),k=O2[r+24|0]|O2[r+25|0]<<8|(O2[r+26|0]<<16|O2[r+27|0]<<24),s0[37+A|0]=k,s0[38+A|0]=k>>>8,s0[39+A|0]=k>>>16,s0[40+A|0]=k>>>24,s0[41+A|0]=a,s0[42+A|0]=a>>>8,s0[43+A|0]=a>>>16,s0[44+A|0]=a>>>24,a=O2[r+20|0]|O2[r+21|0]<<8|(O2[r+22|0]<<16|O2[r+23|0]<<24),k=O2[r+16|0]|O2[r+17|0]<<8|(O2[r+18|0]<<16|O2[r+19|0]<<24),s0[29+A|0]=k,s0[30+A|0]=k>>>8,s0[31+A|0]=k>>>16,s0[32+A|0]=k>>>24,s0[33+A|0]=a,s0[34+A|0]=a>>>8,s0[35+A|0]=a>>>16,s0[36+A|0]=a>>>24,a=O2[r+12|0]|O2[r+13|0]<<8|(O2[r+14|0]<<16|O2[r+15|0]<<24),k=O2[r+8|0]|O2[r+9|0]<<8|(O2[r+10|0]<<16|O2[r+11|0]<<24),s0[21+A|0]=k,s0[22+A|0]=k>>>8,s0[23+A|0]=k>>>16,s0[24+A|0]=k>>>24,s0[25+A|0]=a,s0[26+A|0]=a>>>8,s0[27+A|0]=a>>>16,s0[28+A|0]=a>>>24,a=O2[r+4|0]|O2[r+5|0]<<8|(O2[r+6|0]<<16|O2[r+7|0]<<24),r=O2[0|r]|O2[r+1|0]<<8|(O2[r+2|0]<<16|O2[r+3|0]<<24),s0[13+A|0]=r,s0[14+A|0]=r>>>8,s0[15+A|0]=r>>>16,s0[16+A|0]=r>>>24,s0[17+A|0]=a,s0[18+A|0]=a>>>8,s0[19+A|0]=a>>>16,s0[20+A|0]=a>>>24,P2[68+A>>2]=51,P2[72+A>>2]=1,P2[64+A>>2]=A,P2[e+388>>2]=0}else P2[68+A>>2]=a,P2[64+A>>2]=r;if(n&&(P2[76+A>>2]=1),!w0(r=e+8|0,A+64|0)){if(a=e+368|0,!i)for(;;){if(!h0(r,a,1))break r;if(Q2[f](o,P2[e+368>>2],P2[e+372>>2],0,t,s))break a;if(Q2[f](o,P2[e+376>>2],P2[e+380>>2],0,t,s))break a}for(;;){if(!((e,r)=>{var a,i=0,t=0;if(!(!e|!P2[e>>2])){i=P2[e+28>>2];i:{t:{if(P2[(a=e)+328>>2]){if(i)break t;t=0;break i}if(t=0,P2[e+332>>2]|!i)break i}t=1}i=h0(a,r,t)}return i})(r,a))break r;if(Q2[f](o,P2[e+368>>2],P2[e+372>>2],0,t,s))break a;if(Q2[f](o,P2[e+376>>2],P2[e+380>>2],0,t,s))break}}}f=1;break e}if(i|t|4!=(0|a)|(O2[0|r]|O2[r+(f=1)|0]<<8|(O2[r+2|0]<<16|O2[r+3|0]<<24))!=(O2[5409]|O2[5410]<<8|(O2[5411]<<16|O2[5412]<<24)))break e;P2[e+384>>2]=1,l=i}a=P2[(i=r=e)+396>>2],(e=l+P2[r+392>>2]|0)>>>0>>0&&(a=a+1|0),P2[i+392>>2]=e,P2[r+396>>2]=a,f=0}return R2=96+A|0,f}function c2(e){P2[e>>2]=0,P2[e+4>>2]=0,P2[e+8>>2]=0,P2[e+12>>2]=0}function u2(e){var r;(r=P2[e>>2])&&z2(r),(r=P2[e+8>>2])&&z2(r),P2[e>>2]=0,P2[e+4>>2]=0,P2[e+8>>2]=0,P2[e+12>>2]=0}function b2(e,r,a,i,t,n,f){var o,s=0,c=0;R2=o=R2-16|0;e:if(t){r:switch(0|Q2[t](e,r,a,f)){case 1:P2[P2[e>>2]>>2]=5;break e;case 0:break r;default:break e}if(t=x2(282),P2[i>>2]=t){for(s=27;;){P2[12+o>>2]=s,r=5;r:{a:switch(0|Q2[n](e,t,12+o|0,f)){case 1:if(r=P2[12+o>>2])break r;r=2;default:P2[P2[e>>2]>>2]=r;break e;case 3:break e;case 0:break a}r=P2[12+o>>2]}if(t=r+t|0,!(s=s-r|0))break}if(r=P2[i>>2],P2[i+4>>2]=O2[r+26|0]+27,1&s0[r+5|0]|1399285583!=(O2[0|r]|O2[r+1|0]<<8|(O2[r+2|0]<<16|O2[r+3|0]<<24))|(0!=(O2[r+6|0]|O2[r+7|0]<<8|(O2[r+8|0]<<16|O2[r+9|0]<<24))|0!=(O2[r+10|0]|O2[r+11|0]<<8|(O2[r+12|0]<<16|O2[r+13|0]<<24)))||!(s=O2[r+26|0]))P2[P2[e>>2]>>2]=2;else{for(t=r+27|0;;){P2[12+o>>2]=s,r=5;r:{a:switch(0|Q2[n](e,t,12+o|0,f)){case 1:if(r=P2[12+o>>2])break r;r=2;default:P2[P2[e>>2]>>2]=r;break e;case 3:break e;case 0:break a}r=P2[12+o>>2]}if(t=r+t|0,!(s=s-r|0))break}r=P2[i>>2];r:{if(1!=((t=0)|(a=O2[r+26|0])))for(a=a+-1|0;;){if(255!=O2[27+(r+t|0)|0]){P2[P2[e>>2]>>2]=2;break r}if(!((t=t+1|0)>>>0>>0))break}if(t=O2[27+(r+t|0)|0]+G2(t,255)|0,s=x2((P2[i+12>>2]=t)||1),P2[i+8>>2]=s){if(a=o,t){for(;;){P2[12+o>>2]=t,r=5;a:{i:switch(0|Q2[n](e,s,12+o|0,f)){case 1:if(r=P2[12+o>>2])break a;r=2;default:P2[P2[e>>2]>>2]=r;break r;case 3:break r;case 0:break i}r=P2[12+o>>2]}if(s=r+s|0,!(t=t-r|0))break}r=P2[i>>2]}if(P2[a+12>>2]=O2[r+22|0]|O2[r+23|0]<<8|(O2[r+24|0]<<16|O2[r+25|0]<<24),_0(i),r=P2[i>>2],P2[12+o>>2]==(O2[r+22|0]|O2[r+23|0]<<8|(O2[r+24|0]<<16|O2[r+25|0]<<24))){c=1;break e}P2[P2[e>>2]>>2]=2}else P2[P2[e>>2]>>2]=8}}}else P2[P2[e>>2]>>2]=8}return R2=16+o|0,c}function A2(e,r,a,i,t,n,f){e:{r:if(t){a:switch(0|Q2[t](e,r,a,f)){case 1:break e;case 0:break a;default:break r}if(_0(i),Q2[n](e,P2[i>>2],P2[i+4>>2],0,0,f))break e;if(!Q2[n](e,P2[i+8>>2],P2[i+12>>2],0,0,f))return 1;P2[P2[e>>2]>>2]=5}return 0}return P2[P2[e>>2]>>2]=5,0}function ae(e,r){var a=0,i=0,a=O2[0|e],i=O2[0|r];e:if(!(!a|(0|a)!=(0|i)))for(;;){if(i=O2[r+1|0],!(a=O2[e+1|0]))break e;if(r=r+1|0,e=e+1|0,(0|a)!=(0|i))break}return a-i|0}function k2(e,r){var a,i,t,n=1-(t=1-(i=.5*(a=e*e)))-i;return a*(a*(a*(2480158728947673e-20*a-.001388888888887411)+.0416666666666666)+(i=a*a)*i*(a*(-11359647557788195e-27*a+2.087572321298175e-9)-2.7557314351390663e-7))-e*r+n+t}function l2(e,r){return 1024<=(0|r)?(e*=898846567431158e293,r=(0|r)<2047?r+-1023|0:(e*=898846567431158e293,((0|r)<3069?r:3069)+-2046|0)):-1023<(0|r)||(e*=22250738585072014e-324,r=-2045<(0|r)?r+1022|0:(e*=22250738585072014e-324,(-3066<(0|r)?r:-3066)+2044|0)),d(0,0),d(1,r+1023<<20),e*+m()}function _2(e,r){var a,i,t,n=0,f=0,o=0,s=0,c=0,u=0;R2=t=R2-48|0,g(+e),s=0|_[1],f=0|_[0];e:{r:{a:{if((c=2147483647&(s=o=s))>>>0<=1074752122){if(598523==(1048575&s))break a;if(c>>>0<=1073928572){if(0<(0|o)||0<=(0|o)&&!(f>>>0<0)){m0[r>>3]=n=(e+=-1.5707963267341256)+-6077100506506192e-26,m0[r+8>>3]=e-n-6077100506506192e-26,f=1;break e}m0[r>>3]=n=(e+=1.5707963267341256)+6077100506506192e-26,m0[r+8>>3]=e-n+6077100506506192e-26,f=-1;break e}if(0<(0|o)||0<=(0|o)&&!(f>>>0<0)){m0[r>>3]=n=(e+=-3.1415926534682512)+-1.2154201013012384e-10,m0[r+8>>3]=e-n-1.2154201013012384e-10,f=2;break e}m0[r>>3]=n=(e+=3.1415926534682512)+1.2154201013012384e-10,m0[r+8>>3]=e-n+1.2154201013012384e-10,f=-2;break e}if(c>>>0<=1075594811){if(c>>>0<=1075183036){if(1074977148==(0|c))break a;if(0<(0|o)||0<=(0|o)&&!(f>>>0<0)){m0[r>>3]=n=(e+=-4.712388980202377)+-1.8231301519518578e-10,m0[r+8>>3]=e-n-1.8231301519518578e-10,f=3;break e}m0[r>>3]=n=(e+=4.712388980202377)+1.8231301519518578e-10,m0[r+8>>3]=e-n+1.8231301519518578e-10,f=-3;break e}if(1075388923==(0|c))break a;if(0<(0|o)||0<=(0|o)&&!(f>>>0<0)){m0[r>>3]=n=(e+=-6.2831853069365025)+-2.430840202602477e-10,m0[r+8>>3]=e-n-2.430840202602477e-10,f=4;break e}m0[r>>3]=n=(e+=6.2831853069365025)+2.430840202602477e-10,m0[r+8>>3]=e-n+2.430840202602477e-10,f=-4;break e}if(1094263290>>0)break r}g(+(m0[r>>3]=e=(n=e+-1.5707963267341256*(a=.6366197723675814*e+6755399441055744-6755399441055744))-(u=6077100506506192e-26*a))),f=0|_[1],_[0],s=((o=c>>>20|0)-(f>>>20&2047)|0)<17,f=Y2(a)<2147483648?~~a:-2147483648,s||(u=n,s=o,g(+(m0[r>>3]=e=(n-=e=6077100506303966e-26*a)-(u=20222662487959506e-37*a-(u-n-e)))),o=0|_[1],_[0],(s-(o>>>20&2047)|0)<50)||(u=n,m0[r>>3]=e=(n-=e=20222662487111665e-37*a)-(u=84784276603689e-45*a-(u-n-e))),m0[r+8>>3]=n-e-u;break e}if(2146435072<=c>>>0)m0[r>>3]=e-=e,m0[r+8>>3]=e,f=0;else{for(d(0,0|f),d(1,1048575&o|1096810496),e=+m(),f=0,s=1;;)if(i=(16+t|0)+(f<<3)|0,f=Y2(e)<2147483648?~~e:-2147483648,e=16777216*(e-(m0[i>>3]=n=0|f)),i=(f=1)&s,s=0,!i)break;if(0!=(m0[32+t>>3]=e))f=2;else for(s=1;;)if(s=(f=s)+-1|0,0!=m0[(16+t|0)+(f<<3)>>3])break;f=((e,r,a,i)=>{var t,n,f,o,s,c,u,b=0,A=0,k=0,l=0,_=0,d=0,m=0,g=0,p=0,w=0,h=0;if(R2=u=R2-560|0,d=a+G2(n=0<(0|(A=(a+-3|0)/24|0))?A:0,-24)|0,0<=((t=P2[1901])+(_=i+-1|0)|0))for(A=i+t|0,a=n-_|0;;)if(m0[(320+u|0)+(k<<3)>>3]=(0|a)<0?0:+P2[7616+(a<<2)>>2],a=a+1|0,(0|A)==(0|(k=k+1|0)))break;for(g=d+-24|0,k=(A=0)<(0|t)?t:0,m=(0|i)<1;;){if(m)b=0;else for(l=A+_|0,b=a=0;;)if(b+=m0[(a<<3)+e>>3]*m0[(320+u|0)+(l-a<<3)>>3],(0|i)==(0|(a=a+1|0)))break;if(m0[(A<<3)+u>>3]=b,a=(0|A)==(0|k),A=A+1|0,a)break}s=47-d|0,f=48-d|0,c=d+-25|0,A=t;r:{for(;;){if(b=m0[(A<<3)+u>>3],!(_=((a=0)|(k=A))<1))for(;;)if(m=(480+u|0)+(a<<2)|0,p=b,l=Y2(b*=5.960464477539063e-8)<2147483648?~~b:-2147483648,l=Y2(p+=-16777216*(b=0|l))<2147483648?~~p:-2147483648,P2[m>>2]=l,b=m0[((k=k+-1|0)<<3)+u>>3]+b,(0|A)==(0|(a=a+1|0)))break;b=l2(b,g),b=(b+=-8*v(.125*b))-(0|(m=Y2(b)<2147483648?~~b:-2147483648));a:{i:{t:{if(h=(0|g)<1){if(g)break t;l=P2[476+((A<<2)+u|0)>>2]>>23}else m=(a=(l=P2[(k=476+((A<<2)+u|0)|0)>>2])>>f)+m|0,l=(P2[(w=k)>>2]=k=l-(a<>s;if((0|l)<1)break a;break i}if(l=2,!(.5<=b)){l=0;break a}}if(k=a=0,!_)for(;;)if(o=P2[(w=(480+u|0)+(a<<2)|0)>>2],_=16777215,k=k||(_=16777216,o)?(P2[w>>2]=_-o,1):0,(0|A)==(0|(a=a+1|0)))break;i:if(!h){t:switch(0|c){case 0:P2[(a=476+((A<<2)+u|0)|0)>>2]=8388607&P2[a>>2];break i;case 1:break t;default:break i}P2[(a=476+((A<<2)+u|0)|0)>>2]=4194303&P2[a>>2]}m=m+1|0,2==(0|l)&&(b=1-b,l=2,k)&&(b-=l2(1,g))}if(0!=b)break;if(!(((k=0)|(a=A))<=(0|t))){for(;;)if(k=P2[(480+u|0)+((a=a+-1|0)<<2)>>2]|k,!((0|t)<(0|a)))break;if(k){for(d=g;;)if(d=d+-24|0,P2[(480+u|0)+((A=A+-1|0)<<2)>>2])break;break r}}for(a=1;;)if(a=(k=a)+1|0,P2[(480+u|0)+(t-k<<2)>>2])break;for(k=A+k|0;;){if(m0[(320+u|0)+((_=i+A|0)<<3)>>3]=P2[7616+(n+(A=A+1|0)<<2)>>2],1<=((b=a=0)|i))for(;;)if(b+=m0[(a<<3)+e>>3]*m0[(320+u|0)+(_-a<<3)>>3],(0|i)==(0|(a=a+1|0)))break;if(m0[(A<<3)+u>>3]=b,!((0|A)<(0|k)))break}A=k}16777216<=(b=l2(b,0-g|0))?(i=(480+u|0)+(A<<2)|0,p=b,a=Y2(b*=5.960464477539063e-8)<2147483648?~~b:-2147483648,e=Y2(b=p+-16777216*(0|a))<2147483648?~~b:-2147483648,P2[i>>2]=e,A=A+1|0):(a=Y2(b)<2147483648?~~b:-2147483648,d=g),P2[(480+u|0)+(A<<2)>>2]=a}if(b=l2(1,d),!((0|A)<=-1)){for(a=A;;)if(m0[(a<<3)+u>>3]=b*+P2[(480+u|0)+(a<<2)>>2],b*=5.960464477539063e-8,e=0<(0|a),a=a+-1|0,!e)break;if(!(((_=0)|A)<0))for(e=0<(0|t)?t:0,k=A;;){for(i=e>>>0<_>>>0?e:_,d=A-k|0,b=a=0;;)if(b+=m0[10384+(a<<3)>>3]*m0[(a+k<<3)+u>>3],g=(0|a)!=(0|i),a=a+1|0,!g)break;if(m0[(160+u|0)+(d<<3)>>3]=b,k=k+-1|0,a=(0|A)!=(0|_),_=_+1|0,!a)break}}if((b=0)<=(0|A))for(a=A;;)if(b+=m0[(160+u|0)+(a<<3)>>3],e=0<(0|a),a=a+-1|0,!e)break;if(m0[r>>3]=l?-b:b,b=m0[160+u>>3]-b,(a=1)<=(0|A))for(;;)if(b+=m0[(160+u|0)+(a<<3)>>3],e=(0|a)!=(0|A),a=a+1|0,!e)break;return m0[r+8>>3]=l?-b:b,R2=560+u|0,7&m})(16+t|0,t,(c>>>20|0)-1046|0,f+1|0),e=m0[t>>3],(0|o)<-1||(0|o)<=-1?(m0[r>>3]=-e,m0[r+8>>3]=-m0[8+t>>3],f=0-f|0):(m0[r>>3]=e,o=P2[12+t>>2],P2[r+8>>2]=P2[8+t>>2],P2[r+12>>2]=o)}}return R2=48+t|0,f}function d2(e,r){var a;return e-((a=e*e)*(.5*r-(e*=a)*(a*a*a*(1.58969099521155e-10*a-2.5050760253406863e-8)+(a*(27557313707070068e-22*a-.0001984126982985795)+.00833333333332249)))-r+.16666666666666632*e)}function H2(e){var r,a=0,i=0;R2=r=R2-16|0,g(+e),i=0|_[1],_[0];e:if((i&=2147483647)>>>0<=1072243195)a=1,i>>>0<1044816030||(a=k2(e,0));else if(a=e-e,!(2146435072<=i>>>0)){r:switch(3&_2(e,r)){case 0:a=k2(m0[r>>3],m0[8+r>>3]);break e;case 1:a=-d2(m0[r>>3],m0[8+r>>3]);break e;case 2:a=-k2(m0[r>>3],m0[8+r>>3]);break e;default:break r}a=d2(m0[r>>3],m0[8+r>>3])}return R2=16+r|0,e=a}function ie(e,r,a){var i,t,n,f,o=0;V2(0);if(1<=(0|r))for(t=(i=.5*(r+-1|0))*+a;;)if(n=(o<<2)+e|0,f=V2((e=>{var r,a,i=0,t=0,n=0,f=0,o=0;g(+e),n=0|_[1],a=0|_[0],r=n>>>31|0;e:{r:{a:{i:{o=e;t:{n:{if(1082532651<=(n=2147483647&(i=n))>>>0){if(2146435072==(0|(i&=2147483647))&0>>0|2146435072>>0)return e;if(709.782712893384>>0<1071001155)break i;if(n>>>0<1072734898)break n}if(e=1.4426950408889634*e+m0[10448+(r<<3)>>3],Y2(e)<2147483648){i=~~e;break t}i=-2147483648;break t}i=(1^r)-r|0}t=(e=o+-.6931471803691238*(t=0|i))-(f=1.9082149292705877e-10*t);break a}if(n>>>0<=1043333120)break e;i=0,t=e}f=(o=e)+(t*(e=t-(e=t*t)*(e*(e*(e*(4.1381367970572385e-8*e-16533902205465252e-22)+6613756321437934e-20)-.0027777777777015593)+.16666666666666602))/(2-e)-f)+1,i&&(f=l2(f,i))}return f}return e+1})(-.5*(f=((0|o)-i)/t)*f)),N2[n>>2]=f,(0|(o=o+1|0))==(0|r))break}function te(e,r){var a,i,t,n=0;V2(0);if(1<=(0|r))for(a=r+-1|0;;)if(i=(n<<2)+e|0,t=V2(.5-.5*H2(6.283185307179586*(0|n)/a)),N2[i>>2]=t,(0|(n=n+1|0))==(0|r))break}function ne(e,r){var a,i,t,n,f,o,s,c,u,b=0,A=0,k=0,l=0,_=0,d=0,m=0,A=V0(P2[2720]);e:if(j2(r,P2[e+4>>2],P2[1391])&&j2(r,P2[e>>2],P2[1392])&&(b=P2[e+8>>2],!((b=4==P2[e>>2]?(b+A|0)-P2[e+16>>2]|0:b)>>>(k=P2[1393])))&&j2(r,b,k)){r:{a:{i:{t:{n:{f:{o:switch(P2[e>>2]){case 3:if(!P2[e+16>>2])break r;k=P2[1367],_=P2[1366],d=P2[1365],b=0;break f;case 0:if(!j2(r,P2[e+16>>2],P2[1356]))break e;if(!j2(r,P2[e+20>>2],P2[1357]))break e;if(!j2(r,P2[e+24>>2],P2[1358]))break e;if(!j2(r,P2[e+28>>2],P2[1359]))break e;if(!j2(r,P2[e+32>>2],P2[1360]))break e;if(!j2(r,P2[e+36>>2]+-1|0,P2[1361]))break e;if(!j2(r,P2[e+40>>2]+-1|0,P2[1362]))break e;if(!a2(r,P2[e+48>>2],P2[e+52>>2],P2[1363]))break e;if(t2(r,e+56|0,16))break r;break e;case 1:if(e2(r,P2[e+8>>2]<<3))break r;break e;case 6:break i;case 5:break t;case 4:break n;case 2:break o;default:break a}if(!t2(r,e+16|0,b=P2[1364]>>>3|0))break e;if(t2(r,P2[e+20>>2],P2[e+8>>2]-b|0))break r;break e}for(;;){if(l=(A=G2(b,24))+P2[e+20>>2]|0,!a2(r,P2[l>>2],P2[l+4>>2],d))break e;if(l=A+P2[e+20>>2]|0,!a2(r,P2[l+8>>2],P2[l+12>>2],_))break e;if(!j2(r,P2[16+(A+P2[e+20>>2]|0)>>2],k))break e;if(!((b=b+1|0)>>>0>2]))break}break r}if(!i2(r,A))break e;if(!t2(r,P2[2720],A))break e;if(!i2(r,P2[e+24>>2]))break e;if(!P2[e+24>>2])break r;for(b=0;;){if(!i2(r,P2[(A=b<<3)+P2[e+28>>2]>>2]))break e;if(A=A+P2[e+28>>2]|0,!t2(r,P2[A+4>>2],P2[A>>2]))break e;if(!((b=b+1|0)>>>0>2]))break}break r}if(!t2(r,e+16|0,P2[1378]>>>3|0))break e;if(!a2(r,P2[e+152>>2],P2[e+156>>2],P2[1379]))break e;if(!j2(r,0!=P2[e+160>>2],P2[1380]))break e;if(!e2(r,P2[1381]))break e;if(!j2(r,P2[e+164>>2],P2[1382]))break e;if(!P2[e+164>>2])break r;for(_=P2[1373]>>>3|0,d=P2[1370],l=P2[1369],i=P2[1368],t=P2[1377],n=P2[1376],f=P2[1375],o=P2[1374],s=P2[1372],c=P2[1371],A=0;;){if(b=P2[e+168>>2]+(A<<5)|0,!a2(r,P2[b>>2],P2[b+4>>2],c))break e;if(!j2(r,O2[b+8|0],s))break e;if(!t2(r,b+9|0,_))break e;if(!j2(r,1&s0[b+22|0],o))break e;if(!j2(r,O2[b+22|0]>>>1&1,f))break e;if(!e2(r,n))break e;if(!j2(r,O2[b+23|0],t))break e;t:if(O2[0|(a=b+23|0)]){for(u=b+24|0,b=0;;){if(k=P2[u>>2]+(b<<4)|0,!a2(r,P2[k>>2],P2[k+4>>2],i))return;if(!j2(r,O2[k+8|0],l))return;if(!e2(r,d))break;if((b=b+1|0)>>>0>=O2[0|a])break t}return}if(!((A=A+1|0)>>>0>2]))break}break r}if(!j2(r,P2[e+16>>2],P2[1383]))break e;if(!j2(r,b=V0(P2[e+20>>2]),P2[1384]))break e;if(!t2(r,P2[e+20>>2],b))break e;if(!j2(r,b=V0(P2[e+24>>2]),P2[1385]))break e;if(!t2(r,P2[e+24>>2],b))break e;if(!j2(r,P2[e+28>>2],P2[1386]))break e;if(!j2(r,P2[e+32>>2],P2[1387]))break e;if(!j2(r,P2[e+36>>2],P2[1388]))break e;if(!j2(r,P2[e+40>>2],P2[1389]))break e;if(!j2(r,P2[e+44>>2],P2[1390]))break e;if(t2(r,P2[e+48>>2],P2[e+44>>2]))break r;break e}if(!t2(r,P2[e+16>>2],P2[e+8>>2]))break e}m=1}return m}function m2(e,r){var a,i,t,n,f,o=0,s=0,c=0,u=0,b=0,A=0,k=0;R2=a=R2-16|0;e:if(j2(r,P2[1394],P2[1395])&&j2(r,0,P2[1396])&&j2(r,0!=P2[e+20>>2],P2[1397])){A=16,k=1,s=r;r:{a:{i:{t:{n:{f:{o:{s:{c:{if((0|(o=P2[e>>2]))<=2047){if((0|o)<=575){if(c=1,192==(0|o))break r;if(256==(0|o))break f;if(512!=(0|o))break a;c=9;break r}if(576==(0|o))break c;if(1024==(0|o))break n;if(1152!=(0|o))break a;c=3;break r}if((0|o)<=4607){if(2048==(0|o))break t;if(2304==(0|o))break s;if(4096!=(0|o))break a;c=12;break r}if((0|o)<=16383){if(4608==(0|o))break o;if(8192!=(0|o))break a;c=13;break r}if(16384==(0|o))break i;if(32768!=(0|o))break a;c=15;break r}c=2;break r}c=4;break r}c=5;break r}c=8;break r}c=10;break r}c=11;break r}c=14;break r}A=(o=o>>>0<257)?8:16,k=0,c=o?6:7}if(j2(s,c,P2[1398])){r:{a:{i:{t:{n:{f:{o:{s:{if((0|(o=P2[e+4>>2]))<=44099){if((0|o)<=22049){if(8e3==(0|o))break s;if(16e3!=(0|o))break a;s=5;break r}if(22050==(0|o))break o;if(24e3==(0|o))break f;if(32e3!=(0|o))break a;s=8;break r}if((0|o)<=95999){if(44100==(0|o))break n;if(48e3==(0|o))break t;if(s=1,88200==(0|o))break r;break a}if(96e3==(0|o))break i;if(192e3!=(0|o)){if(176400!=(0|o))break a;s=2;break r}s=3;break r}s=4;break r}s=6;break r}s=7;break r}s=9;break r}s=10;break r}s=11;break r}u=(o>>>0)%1e3|0,o>>>0<=255e3&&(b=s=12,!u)||(b=s=(o>>>0)%10?o>>>0<65536?13:0:14)}if(u=0,j2(r,s,P2[1399])){r:{a:switch(P2[e+12>>2]){case 0:s=P2[e+8>>2]+-1|0;break r;case 1:s=8;break r;case 2:s=9;break r;case 3:break a;default:break r}s=10}if(j2(r,s,P2[1400])&&j2(s=r,o=(o=K2(P2[e+16>>2]+-8|0,30))>>>0<=4?P2[10464+(o<<2)>>2]:0,P2[1401])&&j2(r,0,P2[1402])){r:{if(!P2[e+20>>2]){if(((e,r)=>{if(0<=(0|r)){if(r>>>0<=127)return l(e,r,8);if(r>>>0<=2047)return l(e,r>>>6|192,8)&l(e,63&r|128,8)&1;if(r>>>0<=65535)return l(e,r>>>12|224,8)&l(e,r>>>6&63|128,8)&l(e,63&r|128,8)&1;if(r>>>0<=2097151)return l(e,r>>>18|240,8)&l(e,r>>>12&63|128,8)&l(e,r>>>6&63|128,8)&l(e,63&r|128,8)&1;if(r>>>0<=67108863)return l(e,r>>>24|248,8)&l(e,r>>>18&63|128,8)&l(e,r>>>12&63|128,8)&l(e,r>>>6&63|128,8)&l(e,63&r|128,8)&1;e=l(e,r>>>30|252,8)&l(e,r>>>24&63|128,8)&l(e,r>>>18&63|128,8)&l(e,r>>>12&63|128,8)&l(e,r>>>6&63|128,8)&l(e,63&r|128,8)&1}else e=0;return e})(r,P2[e+24>>2]))break r;break e}if(!((e,r,a)=>{if(15==(0|a)|a>>>0<15){if(!a&r>>>0<=127|a>>>0<0)return l(e,r,8);if(!a&r>>>0<=2047|a>>>0<0)return l(e,(63&a)<<26|r>>>6|192,8)&l(e,63&r|128,8)&1;if(!a&r>>>0<=65535|a>>>0<0)return l(e,(4095&a)<<20|r>>>12|224,8)&l(e,r>>>6&63|128,8)&l(e,63&r|128,8)&1;if(!a&r>>>0<=2097151|a>>>0<0)return l(e,(262143&a)<<14|r>>>18|240,8)&l(e,r>>>12&63|128,8)&l(e,r>>>6&63|128,8)&l(e,63&r|128,8)&1;if(!a&r>>>0<=67108863|a>>>0<0)return l(e,(16777215&a)<<8|r>>>24|248,8)&l(e,r>>>18&63|128,8)&l(e,r>>>12&63|128,8)&l(e,r>>>6&63|128,8)&l(e,63&r|128,8)&1;if(!a&r>>>0<=2147483647|a>>>0<0)return l(e,(1073741823&a)<<2|r>>>30|252,8)&l(e,r>>>24&63|128,8)&l(e,r>>>18&63|128,8)&l(e,r>>>12&63|128,8)&l(e,r>>>6&63|128,8)&l(e,63&r|128,8)&1;e=l(e,254,8)&l(e,(1073741823&a)<<2|r>>>30|128,8)&l(e,r>>>24&63|128,8)&l(e,r>>>18&63|128,8)&l(e,r>>>12&63|128,8)&l(e,r>>>6&63|128,8)&l(e,63&r|128,8)&1}else e=0;return e})(r,P2[e+24>>2],P2[e+28>>2]))break e}if(k||j2(r,P2[e>>2]+-1|0,A)){r:{a:switch(b+-12|0){case 0:if(j2(r,S2[e+4>>2]/1e3|0,8))break r;break e;case 1:if(j2(r,P2[e+4>>2],16))break r;break e;case 2:break a;default:break r}if(!j2(r,S2[e+4>>2]/10|0,16))break e}t=15+a|0,$0(i=r,12+(R2=i=R2-16|(f=0))|(f=0),8+i|0)&&(t=t,n=V(P2[12+i>>2],P2[8+i>>2]),s0[0|t]=n,f=1),R2=16+i|0,f&&(u=0!=(0|j2(r,O2[15+a|0],P2[1403])))}}}}}return R2=16+a|0,u}function g2(e,r,a,i,t,n,f,o){var s,c,u,b,A=0,k=0,l=0,_=P2[(o?5644:5640)>>2],d=P2[(o?5632:5628)>>2];e:{r:{if(!f){if(!P2[n>>2]){if(!j2(e,P2[t>>2],d))break r;if(f2(e,r,a,P2[t>>2]))break e;break r}if(!j2(e,_,d))break r;if(!j2(e,P2[n>>2],P2[1409]))break r;if(!a)break e;for(o=0;;){if(r2(e,P2[(o<<2)+r>>2],P2[n>>2])){if((0|(o=o+1|0))!=(0|a))continue;break e}break}return}for(u=a+i>>>f|0,b=P2[1409],a=0;;){a=(o=a)+(s=u-(k?0:i)|0)|0;a:{if(!P2[(A=(c=k<<2)+n|0)>>2]){if(!j2(e,P2[(A=t+c|(l=0))>>2],d))break r;if(f2(e,(o<<2)+r|0,s,P2[A>>2]))break a;break r}if(l=0,!j2(e,_,d))break r;if(!j2(e,P2[A>>2],b))break r;if(!(a>>>0<=o>>>0))for(;;){if(!r2(e,P2[(o<<2)+r>>2],P2[A>>2]))break r;if((0|(o=o+1|0))==(0|a))break}}if((k=k+(l=1)|0)>>>f)break}}return l}return 1}function A(e,r,a){var i,t=0,n=0;if(a){e:if(t=O2[0|e]){for(;;){if((0|(i=O2[0|r]))!=(0|t)||!(a=a+-1|0)|!i)break;if(r=r+1|0,t=O2[e+1|0],e=e+1|0,!t)break e}n=t}return(255&n)-O2[0|r]|0}}function p2(e){var r,a,i,t,n=0;return R2=t=R2-16|0,i=O2[(r=e)+74|0],s0[r+74|0]=i+(n=-1)|i,S2[r+20>>2]>S2[r+28>>2]&&Q2[P2[r+36>>2]](r,0,0),P2[r+28>>2]=0,P2[r+16>>2]=0,P2[r+20>>2]=0,(4&(i=P2[r>>2])?(P2[r>>2]=32|i,1):(a=P2[r+44>>2]+P2[r+48>>2]|0,P2[r+8>>2]=a,P2[r+4>>2]=a,i<<27>>31))||1==(0|Q2[P2[e+32>>2]](e,15+t|0,1))&&(n=O2[15+t|0]),R2=16+t|0,n}function w2(e){var r,a,i,t;P2[e+112>>2]=0,P2[e+116>>2]=0,a=(r=(i=P2[e+8>>2])-(t=P2[e+4>>2])|0)>>31,P2[e+120>>2]=r,1|(!((0|(P2[e+124>>2]=a))<0||(0|a)<=0&&!(0>>0))?0:1)?P2[e+104>>2]=i:P2[e+104>>2]=t}function c0(e){var r,a=0,i=0,t=0,n=0,f=0,o=0,t=i=P2[e+116>>2];return i|(f=P2[e+112>>2])&&((0|t)<(0|(i=P2[e+124>>2]))||(0|t)<=(0|i)&&!(S2[e+120>>2]>>0))||!(-1<(0|(f=p2(e))))?(P2[e+104>>2]=0,-1):(i=P2[e+8>>2],(n=t=P2[e+116>>2])|(a=P2[e+112>>2])&&(t=(-1^P2[e+124>>2])+n|0,(a=(n=-1^P2[e+120>>2])+a|0)>>>0>>0&&(t=t+1|0),r=(n=a)>>>0<(o=i-(a=P2[e+4>>2])|0)>>>0?0:1,!((0|(o>>=31))<(0|t)||(0|o)<=(0|t)&&r))?P2[e+104>>2]=n+a:P2[e+104>>2]=i,i?(n=(a=1+((a=i)-(i=P2[(t=e)+4>>2])|0)|0)+P2[e+120>>2]|0,e=P2[e+124>>2]+(a>>31)|0,P2[t+120>>2]=n,P2[t+124>>2]=n>>>0>>0?e+1|0:e):i=P2[e+4>>2],O2[0|(e=i+-1|0)]!=(0|f)&&(s0[0|e]=f),f)}function h2(e,r){var a,i=0,t=0,n=0,f=0,o=0,s=0;R2=a=R2-16|0,c[0]=r,i=(i=2147483647&(n=_[0]))+-8388608>>>0<=2130706431?(i=(i=(t=i)>>>7|0)+1065353216|0,(f=t<<=25)>>>0<0?i+1|0:i):2139095040<=i>>>0?(f=(i=n)<<25,2147418112|(t=i>>>7|0)):i?(U(a,t=i,0,0,0,(i=g0(i))+81|0),o=P2[a>>2],s=P2[4+a>>2],f=P2[8+a>>2],65536^P2[12+a>>2]|16265-i<<16):0,P2[e>>2]=o,P2[e+4>>2]=s,P2[e+8>>2]=f,P2[e+12>>2]=-2147483648&n|i,R2=16+a|0}function v2(e,r){var a,i,t,n=0,f=0,o=0;R2=t=R2-16|0,i=a=e,o=r?(U(t,f=(n=r>>31)+r^n,0,0,0,(n=g0(f))+81|0),n=(65536^P2[12+t>>2])+(16414-n<<16)|0,r=-2147483648&r|(n=(f=0+P2[8+t>>2]|0)>>>0>>0?n+1|0:n),n=P2[4+t>>2],P2[t>>2]):r=0,P2[i>>2]=o,P2[a+4>>2]=n,P2[e+8>>2]=f,P2[e+12>>2]=r,R2=16+t|0}function u0(e,r,a,i,t,n,f,o,s){var c,u,b,A,k,l,_,d,m,g,N,G,V,Y,R,p,w=0,h=0,v=0,y=0,C=0,E=0,F=0,B=0,D=0,L=0,I=0,M=0,Q=0,P=0,O=0,T=0,S=0;R2=p=R2-96|0,E=a,B=(131071&(h=f))<<15|n>>>17,M=(h=c=o)<<15|f>>>17,C=-2147483648&(t^s),F=i,O=y=h=65535&t,Q=(131071&(h=L=w=65535&s))<<15|o>>>17,g=s>>>16&32767,N=t>>>16&32767;e:{if(!(N-1>>>0<=32765&&g-1>>>(D=0)<32766)){if(!(!(h=i)&2147418112==(0|(w=v=2147483647&t))?!(r|a):2147418112==(0|w)&i>>>0<0|w>>>0<2147418112)){I=i,C=32768|t;break e}if(!(!(i=o)&2147418112==(0|(t=v=2147483647&s))?!(n|f):2147418112==(0|t)&i>>>0<0|t>>>0<2147418112)){I=o,C=32768|s,r=n,a=f;break e}if(!(r|h|2147418112^w|a)){if(!(i|n|t|f)){C=2147450880,a=r=0;break e}C|=2147418112,a=r=0;break e}if(!(i|n|2147418112^t|f)){if(i=r|h,t=a|w,a=r=0,!(i|t)){C=2147450880;break e}C|=2147418112;break e}if(!(r|h|a|w)){a=r=0;break e}if(!(i|n|t|f)){a=r=0;break e}65535==((i=0)|w)|w>>>0<65535&&(w=r,s=a,o=(i=!(y|F))<<6,h=g0(i?r:F)+32|0,U(80+p|0,w,s,F,y,(r=o+(32==(0|(r=g0(i?a:y)))?h:r)|0)+-15|0),F=P2[88+p>>2],E=P2[84+p>>2],O=P2[92+p>>2],i=16-r|0,r=P2[80+p>>2]),D=i,65535>>0||(t=(a=!(c|L))<<6,o=g0(a?n:c)+32|0,U(p+64|0,n,f,c,L,(s=a=t+(32==(0|(a=g0(a?f:L)))?o:a)|0)+-15|0),a=n=P2[76+p>>2],t=o=P2[72+p>>2],M=(h=P2[68+p>>2])>>>17|(t<<=15),B=(131071&(t=h))<<15|(n=P2[64+p>>2])>>>17,Q=(131071&a)<<15|o>>>17,D=16+(i-s|0)|0)}if(s=b0(i=B,0,r,0),P=a=T2,n=b0(A=n<<15&-32768,0,E,0),v=T2+a|0,v=(t=n+s|0)>>>0>>0?v+1|0:v,a=t,f=b0(A,n=0,r,0),w=T2+a|0,l=(0|a)==(0|(f=w=(t=n+f|0)>>>0>>0?w+1|0:w))&(B=t)>>>0>>0|w>>>0>>0,G=b0(i,0,E,0),_=T2,n=b0(A,0,b=F,0),y=T2+_|0,y=(t=n+G|0)>>>0>>0?y+1|0:y,V=t,o=b0(M,0,r,0),n=T2+y|0,o=L=n=(S=t=t+o|0)>>>0>>0?n+1|0:n,w=(n=(0|v)==(0|P)&a>>>0>>0|v>>>0

>>0)+o|0,t=w=(P=a=(t=v)+S|0)>>>0>>0?w+1|0:w,o=a,Y=b0(i,0,F,0),d=T2,n=b0(a=A,0,A=65536|O,0),w=T2+d|0,w=(a=n+Y|0)>>>0>>0?w+1|0:w,R=a,h=b0(E,0,M,0),n=(u=w)+T2|0,n=(a=a+h|0)>>>0>>0?n+1|0:n,m=a,a=b0(k=2147483647&Q|-2147483648,0,r,0),h=(c=n)+T2|0,a=(T=r=m+a|0)>>>0>>0?h+1|0:h,w=t+r|0,n=Q=w=(r=(n=0)+o|0)>>>0>>0?w+1|0:w,s=n=(o=(O=r)+l|0)>>>0>>0?n+1|0:n,F=(D+(g+N|0)|0)-16383|0,n=b0(b,0,M,0),r=T2,h=b0(i,v=0,A,0),w=T2+r|0,w=(i=h+n|0)>>>0>>0?w+1|0:w,h=D=i,w=(0|r)==(0|(i=w))&h>>>0>>0|i>>>0>>0,r=(n=b0(k,0,E,0))+h|0,h=T2+i|0,h=r>>>0>>0?h+1|0:h,n=E=r,h=n=w+(i=(0|i)==(0|(r=h))&n>>>0>>0|r>>>0>>0)|0,n=v=n>>>0>>0?1:v,l=h,h=(i=r)+(w=(y=(h=((w=0)|y)==(0|L)&S>>>0>>0|L>>>0>>0)+((0|y)==(0|_)&V>>>0>>0|y>>>0<_>>>0)|0)>>>0>>0?1:w)|0,(h=l+(r=(0|r)==(0|(i=h=(w=D=y=(v=y)+E|0)>>>0>>0?h+1|0:h))&w>>>0>>0|i>>>0>>0)|0)>>>0>>0&&(n=n+1|0),r=h,h=b0(k,0,A,0),w=T2+n|0,w=(r=r+h|0)>>>0>>0?w+1|0:w,v=r,y=b0(k,0,b,0),n=T2,E=b0(M,0,A,0),h=T2+n|0,h=(r=E+y|0)>>>0>>0?h+1|0:h,E=r,h=(0|n)==(0|(r=h))&E>>>0>>0|r>>>0>>0,n=r+v|0,v=w+h|0,h=n>>>0>>0?v+1|0:v,b=n,w=i+E|0,n=y=r=(v=0)+D|0,(n=b+(i=(0|i)==(0|(r=w=r>>>0>>0?w+1|0:w))&n>>>0>>0|r>>>0>>0)|0)>>>0>>0&&(h=h+1|0),E=n,(u=(n=((w=0)|u)==(0|c)&m>>>0>>0|c>>>0>>0)+((0|u)==(0|d)&R>>>0>>0|u>>>0>>0)|0)>>>0>>0&&(w=1),v=(n=u+((0|a)==(0|c)&T>>>0>>0|a>>>0>>0)|0)+(v=r)|0,v=(a=(i=a)+y|0)>>>0>>0?v+1|0:v,i=u=a,w=h=(i=(r=(0|r)==(0|(a=v))&i>>>0>>0|a>>>0>>0)+E|0)>>>0>>0?h+1|0:h,h=i,v=(r=a)+(n=(t=(i=((n=0)|t)==(0|Q)&O>>>0

>>0|Q>>>0>>0)+((0|t)==(0|L)&P>>>0>>0|t>>>0>>0)|0)>>>0>>0?1:n)|0,(a=h+(r=(0|a)==(0|(t=v=(i=t+u|0)>>>0>>0?v+1|0:v))&(r=i)>>>0>>0|t>>>0>>0)|0)>>>0>>0&&(w=w+1|0),r=a,65536&(a=w)?F=F+1|0:(y=f>>>31|0,w=a<<1|r>>>31,r=r<<1|t>>>31,a=w,w=t<<1|i>>>31,i=i<<1|s>>>31,t=w,B=(h=B)<<1,f=w=f<<1|h>>>31,h=s<<1|o>>>31,o=o<<1|y,s=h),32767<=(0|F))C|=2147418112,a=r=0;else{r:{if((0|F)<=0){if((n=1-F|0)>>>0<=127){U(48+p|0,B,f,o,s,h=F+127|0),U(32+p|0,i,t,r,a,h),x(16+p|0,B,f,o,s,n),x(p,i,t,r,a,n),B=0!=(P2[48+p>>2]|P2[56+p>>2])|0!=(P2[52+p>>2]|P2[60+p>>2])|(P2[32+p>>2]|P2[16+p>>2]),f=P2[36+p>>2]|P2[20+p>>2],o=P2[40+p>>2]|P2[24+p>>2],s=P2[44+p>>2]|P2[28+p>>2],i=P2[p>>2],t=P2[4+p>>2],a=P2[12+p>>2],r=P2[8+p>>2];break r}a=r=0;break e}a=65535&a|F<<16}I|=r,C|=a,(!o&-2147483648==(0|s)?!(f|B):-1<(0|s))?o|B|-2147483648^s|f?(r=i,a=t):(y=C,w=t,(a=(r=1&i)+i|0)>>>0>>0&&(w=w+1|0),r=a,I=t=(i=(0|t)==(0|(a=w))&r>>>0>>0|a>>>0>>0)+I|0,C=y=t>>>0>>0?y+1|0:y):(v=C,I=t=(i=(0|(y=t))==(0|(a=y=(r=i+1|0)>>>0<1?y+1|0:y))&r>>>0>>0|a>>>0>>0)+I|0,C=v=t>>>0>>0?v+1|0:v)}}P2[e>>2]=r,P2[e+4>>2]=a,P2[e+8>>2]=I,P2[e+12>>2]=C,R2=96+p|0}function y2(e,r,a,i,t,n,f,o,s){var c,u=0,b=0,A=0,k=0,l=0,_=0,d=0,m=0,g=0;R2=c=R2-112|0,A=o,l=2147483647&s,b=a+-1|0,m=-1==(0|(k=u=r+-1|0))&-1==(0|(b=-1!=(0|u)?b+1|0:b)),u=_=2147483647&t,b=(u=(k=(d=i)+(b=(0|a)==(0|b)&k>>>0>>0|b>>>0>>0)|0)>>>0>>0?u+1|0:u)+-1|0,u=k=k+-1|0;e:{if((-1==(0|u)&2147418111==(0|(b=-1!=(0|u)?b+1|0:b))?m:2147418111>>0)||(b=f+-1|0,m=-1!=(0|(k=u=n+-1|0))|-1!=(0|(b=-1!=(0|u)?b+1|0:b)),u=l,u=(u=(k=(b=(0|f)==(0|b)&k>>>0>>0|b>>>0>>0)+A|0)>>>0>>0?u+1|0:u)+-1|0,!(-1==(0|(b=k+-1|0))&2147418111==(0|(u=-1!=(0|b)?u+1|0:u))?m:2147418111==(0|u)&-1!=(0|b)|u>>>0<2147418111))){if(!(!d&2147418112==(0|_)?!(r|a):2147418112==(0|_)&d>>>0<0|_>>>0<2147418112)){o=i,s=32768|t,n=r,f=a;break e}if(!(!A&2147418112==(0|l)?!(n|f):2147418112==(0|l)&A>>>0<0|l>>>0<2147418112)){s|=32768;break e}if(!(r|d|2147418112^_|a)){o=(i=!(r^n|(u=i)^o|a^f|t^s^-2147483648))?0:u,s=i?2147450880:t,n=i?0:r,f=i?0:a;break e}if(!(n|A|2147418112^l|f))break e;if(!(r|d|a|_)){if(n|A|f|l)break e;n&=r,f&=a,o&=i,s&=t;break e}if(!(n|A|f|l)){n=r,f=a,o=i,s=t;break e}}if(_=(u=b=(0|A)==(0|d)&(0|l)==(0|_)?(0|a)==(0|f)&r>>>0>>0|a>>>0>>0:(0|l)==(0|_)&d>>>0>>0|_>>>0>>0)?n:r,l=u?f:a,k=u?o:i,u=65535&(d=A=u?s:t),i=b?i:o,m=(g=t=b?t:s)>>>16&32767,(A=A>>>16&32767)||(o=(t=!(u|k))<<6,s=g0(t?_:k)+32|0,U(96+c|0,_,l,k,u,(t=o+(32==(0|(t=g0(t?l:u)))?s:t)|0)+-15|0),k=P2[104+c>>2],_=P2[96+c>>2],l=P2[100+c>>2],A=16-t|0,u=P2[108+c>>2]),n=b?r:n,f=b?a:f,r=i,a=65535&g,r=m?a:(t=(i=!((o=r)|a))<<6,s=g0(i?n:r)+32|0,U(80+c|0,n,f,o,a,(r=t+(32==(0|(r=g0(i?f:a)))?s:r)|0)+-15|0),m=16-r|0,n=P2[80+c>>2],f=P2[84+c>>2],i=P2[88+c>>2],P2[92+c>>2]),o=(a=i)<<3|f>>>29,s=524288|(b=r<<3|a>>>29),t=(r=k)<<3|l>>>29,k=i=u<<3|r>>>29,b=d^g,a=u=f<<3|(r=n)>>>29,i=r<<=3,(n=A-m|0)&&(i=127>>0?(u=s=o=0,1):(U(c+64|0,r,a,o,s,128-n|0),x(48+c|0,r,a,o,s,n),o=P2[56+c>>2],s=P2[60+c>>2],u=P2[52+c>>2],P2[48+c>>2]|(0!=(P2[64+c>>2]|P2[72+c>>2])|0!=(P2[68+c>>2]|P2[76+c>>2])))),f=u,k|=524288,u=l<<3|(r=_)>>>29,a=r<<3,(0|b)<-1||(0|b)<=-1){if(!((r=a-(l=i)|0)|(n=(_=t-o|0)-(i=(0|f)==(0|u)&a>>>0>>0|u>>>0>>0)|0)|(a=u-((a>>>0>>0)+f|0)|0)|(f=(k-((t>>>0>>0)+s|0)|0)-(_>>>0>>0)|0))){s=o=f=n=0;break e}524287>>0||(o=r,t=(i=!(n|f))<<6,s=g0(i?r:n)+32|0,U(32+c|0,o,a,n,f,r=(r=t+(32==(0|(r=g0(i?a:f)))?s:r)|0)+-12|0),A=A-r|0,n=P2[40+c>>2],f=P2[44+c>>2],r=P2[32+c>>2],a=P2[36+c>>2])}else b=f+u|0,(a=(r=i)+a|0)>>>0>>0&&(b=b+1|0),r=a,f=(0|f)==(0|(a=b))&r>>>0>>0|a>>>0>>0,b=s+k|0,(i=t+o|0)>>>0>>0&&(b=b+1|0),t=f+(n=i)|0,i=b,i=t>>>0>>0?i+1|0:i,n=t,1048576&(f=i)&&(r=1&r|(1&a)<<31|r>>>1,a=n<<31|a>>>1,A=A+1|0,n=(1&f)<<31|n>>>1,f=f>>>1|0);u=-2147483648&d,32767<=((o=0)|A)?(s=2147418112|u,f=n=0):((t=0)<(0|A)?t=A:(U(16+c|0,r,a,n,f,A+127|0),x(c,r,a,n,f,1-A|0),r=P2[c>>2]|(0!=(P2[16+c>>2]|P2[24+c>>2])|0!=(P2[20+c>>2]|P2[28+c>>2])),a=P2[4+c>>2],n=P2[8+c>>2],f=P2[12+c>>2]),o=o|(7&f)<<29|n>>>3,t=u|f>>>3&65535|t<<16,n=u=n<<29,f=(7&a)<<29|r>>>3|(i=0),u=t,b=i=a>>>3|n,(a=(r=4<(t=7&r)>>>0)+f|0)>>>0>>0&&(b=b+1|0),r=a,(n=(i=(0|i)==(0|(a=b))&r>>>0>>0|a>>>0>>0)+o|0)>>>0>>0&&(u=u+1|0),i=(t=4==(0|t))?1&r:0,s=u,u=a+(t=0)|0,(a=(o=n)+(r=(0|t)==(0|(f=u=(a=r+i|0)>>>0>>0?u+1|0:u))&(r=n=a)>>>0>>0|u>>>0>>0)|0)>>>0>>0&&(s=s+1|0),o=a)}P2[e>>2]=n,P2[e+4>>2]=f,P2[e+8>>2]=o,P2[e+12>>2]=s,R2=112+c|0}function C2(e,r){var a,i=0,t=0,n=0,f=0,o=0,s=0;R2=a=R2-16|0,g(+r),n=(i=o=2147483647&(r=0|_[1]))+-1048576|0,i=2145386495==(0|(n=(t=f=0|_[0])>>>0<0?n+1|0:n))|n>>>0<2145386495?(o=t<<28,n=(15&i)<<28|t>>>4,i=1006632960+(i>>>4|0)|0,(t=n)>>>0<0?i+1|0:i):2146435072==(0|i)&0<=t>>>0|2146435072>>0?(o=f<<28,t=(15&(i=r))<<28|(n=f)>>>4,2147418112|(f=i>>>4|0)):i|t?(U(a,t,n=i,0,0,(i=1==(0|i)&t>>>0<0|i>>>0<1?g0(f)+32|0:g0(i))+49|0),s=P2[a>>2],o=P2[4+a>>2],t=P2[8+a>>2],65536^P2[12+a>>2]|15372-i<<16):t=o=0,P2[e>>2]=s,P2[e+4>>2]=o,P2[e+8>>2]=t,P2[e+12>>2]=-2147483648&r|i,R2=16+a|0}function E2(e,r,a,i,t,n,f,o){var s,c,u=0,b=0,A=0,u=1,b=c=2147483647&i,k=a;e:if(!(!a&2147418112==(0|c)?e|r:2147418112==(0|c)&0>>0|2147418112>>0)&&!(!(c=f)&2147418112==(0|(A=s=2147483647&o))?t|n:2147418112==(0|s)&0>>0|2147418112>>0)){if(!(e|t|c|k|r|n|b|A))return 0;if(0<(0|(k=i&o))||0<=(0|k)&&!((a&f)>>>0<0)){if(u=-1,(0|a)==(0|f)&(0|i)==(0|o)?(0|r)==(0|n)&e>>>0>>0|r>>>0>>0:(0|i)<(0|o)||(0|i)<=(0|o)&&!(f>>>0<=a>>>0))break e;return 0!=(e^t|a^f)|0!=(r^n|i^o)}u=-1,((0|a)==(0|f)&(0|i)==(0|o)?(0|r)==(0|n)&t>>>0>>0|n>>>0>>0:(0|o)<(0|i)||(0|o)<=(0|i)&&!(a>>>0<=f>>>0))||(u=0!=(e^t|a^f)|0!=(r^n|i^o))}return u}function F2(e,r,a,i,t){var n,f=0,o=0,s=0,f=-1,o=n=2147483647&i,c=a;e:if(!((!a&2147418112==(0|n)?e|r:2147418112==(0|n)&0>>0|2147418112>>0)||2147418112!=(0|(s=n=2147483647&t))&&2147418112>>0)){if(!(e|c|r|o|s))return 0;if(0<(0|(c=i&t))||0<=(0|c)){if(!a&(0|i)==(0|t)?!r&e>>>0<0|r>>>0<0:(0|i)<(0|t)||(0|i)<=(0|t)&&!(0<=a>>>0))break e;return 0!=(e|a)|0!=(r|i^t)}(!a&(0|i)==(0|t)?!r&0>>0|0>>0:(0|t)<(0|i)||(0|t)<=(0|i)&&!(a>>>0<=0))||(f=0!=(e|a)|0!=(r|i^t))}return f}function B2(e,r,a,i,t,n,f,o,s){P2[e>>2]=r,P2[e+4>>2]=a,P2[e+8>>2]=i,P2[e+12>>2]=65535&t|(s>>>16&32768|t>>>16&32767)<<16}function D2(e,r){var a,i,t,n=0,f=0,o=0;R2=t=R2-16|0,i=a=e,n=r?(U(t,n=r,0,0,0,112-(r=31^g0(r))|0),r=(65536^P2[12+t>>2])+(r+16383<<16)|0,(f=0+P2[8+t>>2]|0)>>>0>>0&&(r=r+1|0),o=P2[4+t>>2],P2[t>>2]):r=0,P2[i>>2]=n,P2[a+4>>2]=o,P2[e+8>>2]=f,P2[e+12>>2]=r,R2=16+t|0}function L2(e,r,a,i,t,n,f,o,s){var c;y2(R2=c=R2-16|0,r,a,i,t,n,f,o,-2147483648^s),r=P2[4+c>>2],P2[e>>2]=P2[c>>2],P2[e+4>>2]=r,r=P2[12+c>>2],P2[e+8>>2]=P2[8+c>>2],P2[e+12>>2]=r,R2=16+c|0}function I2(e,r,a,i,t,n){var f;R2=f=R2-80|0,16384<=(0|n)?(u0(32+f|0,r,a,i,t,0,0,0,2147352576),i=P2[40+f>>2],t=P2[44+f>>2],r=P2[32+f>>2],a=P2[36+f>>2],(0|n)<32767?n=n+-16383|0:(u0(16+f|0,r,a,i,t,0,0,0,2147352576),n=((0|n)<49149?n:49149)+-32766|0,i=P2[24+f>>2],t=P2[28+f>>2],r=P2[16+f>>2],a=P2[20+f>>2])):-16383<(0|n)||(u0(f+64|0,r,a,i,t,0,0,0,65536),i=P2[72+f>>2],t=P2[76+f>>2],r=P2[64+f>>2],a=P2[68+f>>2],-32765<(0|n)?n=n+16382|0:(u0(48+f|0,r,a,i,t,0,0,0,65536),n=(-49146<(0|n)?n:-49146)+32764|0,i=P2[56+f>>2],t=P2[60+f>>2],r=P2[48+f>>2],a=P2[52+f>>2])),u0(f,r,a,i,t,0,0,0,n+16383<<16),r=P2[12+f>>2],P2[e+8>>2]=P2[8+f>>2],P2[e+12>>2]=r,r=P2[4+f>>2],P2[e>>2]=P2[f>>2],P2[e+4>>2]=r,R2=80+f|0}function M2(e,r,a,i,t){var n,f,o,s=b0(r,a,0,0),c=T2,u=b0(0,0,i,t);c=T2+c|0,n=(s=s+u|0)+(f=b0(t,0,a,0))|0,s=T2+(s>>>0>>0?1+c|0:c)|0,c=b0(i,0,r,0),o=T2,u=b0(a,0,i,0),a=n>>>0>>0?1+s|0:s,(n=(s=(i=o+u|0)>>>0>>0?T2+1|0:T2)+n|0)>>>0>>0&&(a=a+1|0),r=b0(r,0,t,0)+i|0,t=T2,(t=n+(i=r>>>0>>0?t+1|0:t)|0)>>>0>>0&&(a=a+1|0),P2[e+8>>2]=t,P2[e+12>>2]=a,P2[e>>2]=c,P2[e+4>>2]=r}function fe(e,r,a,i,t,n,f,o,s){var c,u,b,N,G,A,V,k,l,_=0,d=0,m=0,g=0,p=0,w=0,h=0,v=0,y=0,C=0,E=0,F=0,B=0,D=0,L=0,I=0,M=0,Q=0,P=0,O=0,S=0,Y=0;R2=l=R2-192|0,Q=o,O=65535&s,h=i,p=65535&t,M=-2147483648&(t^s),v=s>>>16&32767;e:{c=t>>>16&32767;r:{if(!(c-1>>>0<=32765&&v+-1>>>0<32766)){if(!(!(_=i)&2147418112==(0|(m=d=2147483647&t))?!(r|a):2147418112==(0|d)&_>>>0<0|d>>>0<2147418112)){S=i,M=32768|t;break r}if(!(!(i=o)&2147418112==(0|(t=d=2147483647&s))?!(n|f):2147418112==(0|d)&i>>>0<0|d>>>0<2147418112)){S=o,M=32768|s,r=n,a=f;break r}if(!(r|_|2147418112^m|a)){if(!(i|n|2147418112^t|f)){a=r=0,M=2147450880;break r}M|=2147418112,a=r=0;break r}if(!(i|n|2147418112^t|f)){a=r=0;break r}if(!(r|_|a|m))break e;if(!(i|n|t|f)){M|=2147418112,a=r=0;break r}65535==((d=0)|m)|m>>>0<65535&&(s=r,o=(i=!(p|h))<<6,_=g0(i?r:h)+32|0,U(176+l|0,s,a,h,p,(r=o+(32==(0|(r=g0(i?a:p)))?_:r)|0)+-15|0),d=16-r|0,h=P2[184+l>>2],p=P2[188+l>>2],a=P2[180+l>>2],r=P2[176+l>>2]),65535>>0||(t=(i=!(Q|O))<<6,o=g0(i?n:Q)+32|0,U(160+l|0,n,f,Q,O,(i=t+(32==(0|(i=g0(i?f:O)))?o:i)|0)+-15|0),d=(i+d|0)-16|0,Q=P2[168+l>>2],O=P2[172+l>>2],n=P2[160+l>>2],f=P2[164+l>>2])}g=(P=t=65536|O)<<15|(i=G=Q)>>>17,M2(144+l|0,i=i<<15|f>>>17,_=t=g,o=-102865788-i|0,s=1963258675-(_+(4192101508>>0)|0)|0),M2(128+l|0,0-(_=P2[152+l>>2])|0,0-(P2[156+l>>2]+(0<_>>>0)|0)|0,o,s),M2(112+l|0,s=(o=P2[136+l>>2])<<1|P2[132+l>>2]>>>31,o=P2[140+l>>2]<<1|o>>>31,i,t),M2(96+l|0,s,_=o,0-(o=P2[120+l>>2])|0,0-(P2[124+l>>2]+(0>>0)|0)|0),o=P2[104+l>>2],m=P2[108+l>>2]<<1|o>>>31,M2(80+l|0,s=o<<1|P2[100+l>>2]>>>31,m,i,t),M2(l+64|0,s,m,0-(o=P2[88+l>>2])|0,0-(P2[92+l>>2]+(0>>0)|0)|0),M2(48+l|0,s=(o=P2[72+l>>2])<<1|P2[68+l>>2]>>>31,o=P2[76+l>>2]<<1|o>>>31,i,t),M2(32+l|0,s,_=o,0-(o=P2[56+l>>2])|0,0-(P2[60+l>>2]+(0>>0)|0)|0),o=P2[40+l>>2],m=P2[44+l>>2]<<1|o>>>31,M2(16+l|0,s=o<<1|P2[36+l>>2]>>>31,m,i,t),M2(l,s,m,0-(o=P2[24+l>>2])|0,0-(P2[28+l>>2]+(0>>0)|0)|0),Y=(c-v|0)+d|0,o=P2[8+l>>2],d=(_=P2[12+l>>2]<<1|o>>>31)+-1|0,-1!=(0|(s=(P2[4+l>>2]>>>31|(s=o<<1))-1|0))&&(d=d+1|0),g=b0(o=s,E=_=0,C=t,m=0),c=t=T2,o=b0(F=d,v=0,_=i,0),d=T2+t|0,d=(i=o+g|0)>>>0>>0?d+1|0:d,o=i,i=d,w=b0(s,E,_,w),_=(d=o)+T2|0,_=(t=0+w|0)>>>0>>0?_+1|0:_,w=t,_=(0|d)==(0|(t=_))&w>>>0>>0|_>>>0>>0,d=(0|i)==(0|c)&d>>>0>>0|i>>>0>>0,o=i,i=b0(F,v,C,m)+i|0,m=d+T2|0,m=i>>>0>>0?m+1|0:m,i=_+(o=i)|0,_=m,o=(L=i)>>>0>>0?_+1|0:_,C=b0(s,E,D=(131071&(i=f))<<15|n>>>17,0),B=i=T2,m=b0(F,v,y=(d=n)<<15&-32768,0),d=T2+i|0,i=d=(_=m+C|0)>>>0>>0?d+1|0:d,u=b0(s,E,y,0),d=_+T2|0,d=(0|_)==(0|(d=(y=0+u|0)>>>0>>0?d+1|0:d))&y>>>0<0|d>>>0<_>>>0,_=(0|i)==(0|B)&_>>>0>>0|i>>>0>>0,g=i,i=b0(F,v,D,I)+i|0,m=_+T2|0,m=i>>>0>>0?m+1|0:m,_=(g=(i=d+(_=i)|0)>>>0<_>>>0?m+1|0:m)+t|0,_=(i=w+(d=i)|0)>>>0>>0?_+1|0:_,d=o,_=d=(t=(i=(0|t)==(0|(C=_))&(c=i)>>>0>>0|_>>>0>>0)+L|0)>>>0>>0?d+1|0:d,(t=t+(i=0!=(0|c)|0!=(0|C))|0)>>>0>>0&&(_=_+1|0),o=b0(t=0-(d=t)|0,w=0,s,E),B=i=T2,y=b0(F,v,t,w),L=t=T2,w=b0(s,E,D=0-((0>>0)+_|0)|0,_=0),d=T2+t|0,d=(g=w+y|0)>>>0>>0?d+1|0:d,m=i+(t=g)|0,m=(0|B)==(0|(i=m=(w=0+o|0)>>>0>>0?m+1|0:m))&(g=w)>>>0>>0|i>>>0>>0,g=(0|d)==(0|L)&t>>>0>>0|d>>>0>>0,t=b0(F,v,D,_)+d|0,_=g+T2|0,_=t>>>0>>0?_+1|0:_,D=t=m+(o=t)|0,o=_=t>>>0>>0?_+1|0:_,t=0-c|0,L=b0(I=0-((0>>0)+C|0)|0,0,s,E),y=T2,_=b0(C=t,0,F,v),d=T2+y|0,t=(m=t=_+L|0)>>>0<_>>>0?d+1|0:d,C=b0(s,E,C,0),d=(_=m)+T2|0,d=(0|_)==(0|(d=(s=0+C|0)>>>0>>0?d+1|0:d))&s>>>0<0|d>>>0<_>>>0,_=(0|t)==(0|y)&_>>>0>>0|t>>>0>>0,s=t,t=b0(I,0,F,v)+t|0,g=_+T2|0,_=g=t>>>0>>0?g+1|0:g,_=(_=(t=d+(s=t)|0)>>>0>>0?_+1|0:_)+i|0,_=(t=w+(s=t)|0)>>>0>>0?_+1|0:_,s=t,d=o,_=d=(o=(i=(0|i)==(0|(t=_))&s>>>0>>0|_>>>0>>0)+D|0)>>>0>>0?d+1|0:d,g=i=o,m=t+-1|0,d=o=i=s+-2|0,d=(_=(s=g+(t=(0|t)==(0|(i=m=i>>>0<4294967294?m+1|0:m))&d>>>0>>0|i>>>0>>0)|0)>>>0>>0?_+1|0:_)+-1|0,d=-1!=(0|(t=s+-1|0))?d+1|0:d,g=b0(v=t,F=s=0,y=(_=h)<<2|a>>>30,D=0),m=w=s=T2,_=b0(I=(1073741823&(s=a))<<2|r>>>30,s=0,u=d,s),m=T2+m|0,B=(0|w)==(0|(C=m=(t=_+g|0)>>>0<_>>>0?m+1|0:m))&(_=t)>>>0>>0|m>>>0>>0,g=m,t=b0(L=i,w=m=0,b=-262145&((1073741823&p)<<2|h>>>30)|262144,d=0),g=T2+g|0,(_=(i=(0|C)==(0|(t=g=(i=t+_|0)>>>0>>0?g+1|0:g))&(h=i)>>>0<_>>>0|t>>>0>>0)+B|0)>>>0>>0&&(d=1),i=(m=b0(u,s,b,0))+_|0,_=T2+d|0,d=i>>>0>>0?_+1|0:_,m=b0(v,F,b,0),_=T2,a=i,p=b0(y,D,u,s),g=T2+_|0,g=(i=p+m|0)>>>0

>>0?g+1|0:g,p=i,d=d+(g=(0|_)==(0|(i=g))&p>>>0>>0|i>>>0<_>>>0)|0,g=(_=m=a+i|0)>>>0>>0?d+1|0:d,a=_,m=t+p|0,_=p=i=(d=0)+h|0,(_=a+(t=(0|t)==(0|(i=m=i>>>0>>0?m+1|0:m))&_>>>0>>0|i>>>0>>0)|0)>>>0>>0&&(g=g+1|0),A=_,t=p,d=i,h=b0(I,0,L,w),m=T2,B=b0(C=o,0,y,D),_=T2+m|0,E=o=B+h|0,h=(0|m)==(0|(o=_=o>>>0>>0?_+1|0:_))&E>>>0>>0|_>>>0>>0,m=_,V=t,k=h,h=b0(v,F,N=r<<2&-4,a=_=0),m=T2+m|0,m=(t=h+E|0)>>>0>>0?m+1|0:m,h=B=t,d=(_=(m=k+(o=(0|o)==(0|(t=m))&h>>>0>>0|t>>>0>>0)|0)>>>0>>0?1:_)+d|0,d=(o=V+m|0)>>>0>>0?d+1|0:d,h=o,m=g,(_=(i=(0|i)==(0|(o=d))&h>>>0

>>0|d>>>0>>0)+A|0)>>>0>>0&&(m=m+1|0),V=_,p=h,E=o,A=b0(u,s,N,a),u=T2,s=b0(b,0,C,0),g=T2+u|0,g=(i=s+A|0)>>>0>>0?g+1|0:g,b=i,_=b0(y,D,L,w),d=(s=g)+T2|0,d=(i=i+_|0)>>>0<_>>>0?d+1|0:d,y=i,g=b0(v,F,I,0),_=T2+d|0,_=(v=i=i+g|0)>>>0>>0?_+1|0:_,g=m,d=((d=s=(_=((F=0)|(i=_))==(0|d)&v>>>0>>0|_>>>0>>0)+(d=(m=(0|s)==(0|u)&b>>>0>>0|s>>>0>>0)+(s=(0|s)==(0|d)&y>>>0>>0|d>>>0>>0)|0)|0)|F)+E|0,D=s=(o=(0|o)==(0|(p=d=(s=(_=0|i)+p|0)>>>0<_>>>0?d+1|0:d))&(E=s)>>>0>>0|d>>>0>>0)+V|0,s=g=s>>>0>>0?g+1|0:g,g=E,h=p,F=B,L=b0(L,w,N,a),w=T2,_=b0(I,0,C,0),m=T2+w|0,d=m=(o=_+L|0)>>>0<_>>>0?m+1|0:m,_=((m=0)|(c=d))==(0|w)&o>>>0>>0|d>>>0>>0,o=d+F|0,d=(_|m)+t|0,d=o>>>0>>0?d+1|0:d,_=c=o,B=g,t=_=(0|t)==(0|(o=d))&_>>>0>>0|d>>>0>>0,_=d+v|0,g=(m=(t=t+(i=((g=0)|o)==(0|(_=(i=g+c|0)>>>0>>0?_+1|0:_))&i>>>0>>0|_>>>0>>0)|0)>>>0>>0?1:m)+h|0,_=s,(t=(i=(0|p)==(0|(s=g=(o=i=B+t|0)>>>0>>0?g+1|0:g))&i>>>0>>0|s>>>0

>>0)+D|0)>>>0>>0&&(_=_+1|0),i=t,r=131071==(0|(t=_))|_>>>0<131071?(_=r<<17,h=(r=y=F=0)-(a=0!=(0|(d=b0(o,F,p=n,y)))|0!=(0|(m=T2)))|0,b=_-(r>>>0>>0)|0,c=0-d|0,w=0-((0>>0)+m|0)|0,D=b0(s,a=0,p,y),I=r=T2,d=b0(o,F,f,v=0),m=T2+r|0,m=(_=d+D|0)>>>0>>0?m+1|0:m,E=h-(_=((C=0)|(B=d=r=_))==(0|w)&c>>>0<(_=C)>>>0|w>>>0>>0)|0,b=b-(h>>>0<_>>>0)|0,_=b0(i,0,p,y),d=T2,p=b0(o,F,Q,0),g=T2+d|0,g=(_=p+_|0)>>>0

>>0?g+1|0:g,p=b0(s,a,f,v),d=T2+g|0,g=d=(_=p+_|0)>>>0

>>0?d+1|0:d,d=(d=(0|m)==(0|I)&r>>>0>>0|m>>>0>>0)+g|0,d=(r=m+_|0)>>>0>>0?d+1|0:d,m=r,r=d,_=b0(o,s,P,0),p=T2,h=m,d=(m=b0(n,f,t,0))+_|0,_=T2+p|0,_=d>>>0>>0?_+1|0:_,m=(g=b0(i,t,f,v))+d|0,_=r+(_=a=(_=b0(s,a,Q,O))+m|0)|(d=0),h=E-(r=a=h+d|0)|0,a=b-((E>>>0>>0)+(r>>>0>>0?_+1|0:_)|0)|0,Y=Y+-1|0,Q=c-C|0,w-((c>>>0>>0)+B|0)|0):(v=s>>>1|0,g=r<<16,o=(1&s)<<31|o>>>1,s=s>>>1|(d=i<<31),p=a-(_=(I=m=0)!=(0|(r=b0(o,I,n,0)))|0!=(0|(d=_=T2)))|0,k=g-(a>>>0<_>>>0)|0,E=0-r|0,g=F=0-((0>>0)+d|0)|0,C=b0(o,I,f,w=0),A=r=T2,N=t<<31|i>>>1|m,v=b0(d=B=v|i<<31,0,n,0),_=T2+r|0,r=_=(a=v+C|0)>>>0>>0?_+1|0:_,D=p-(_=((y=0)|(L=_=a))==(0|g)&E>>>0>>0|g>>>0<_>>>0)|0,k=k-(p>>>0<_>>>0)|0,d=b0(f,w,d,m),m=T2,p=g=(_=t)>>>1|0,_=(g=b0(v=(1&_)<<31|i>>>1,0,n,0))+d|0,d=T2+m|0,d=_>>>0>>0?d+1|0:d,m=(g=b0(o,I,Q,0))+_|0,_=T2+d|0,m=(d=m)>>>0>>0?_+1|0:_,m=(_=(0|r)==(0|A)&a>>>0>>0|r>>>0>>0)+m|0,r=(_=r=(a=r)+d|0)>>>0>>0?m+1|0:m,a=b0(o,s,P,0),d=T2,m=_,i=b0(n,f,t>>>1|0,0),_=T2+d|0,_=(a=i+a|0)>>>0>>0?_+1|0:_,a=(i=b0(f,w,v,p))+a|0,_=T2+_|0,d=r+(_=a=(i=b0(B,N,Q,O))+a|0)|(i=0),h=D-(r=a=m+i|0)|0,a=k-((D>>>0>>0)+(r>>>0>>0?d+1|0:d)|0)|0,i=v,t=p,Q=E-y|0,F-((E>>>0>>0)+L|0)|0),16384<=(0|Y)?(M|=2147418112,a=r=0):(m=Y+16383|0,(0|Y)<=-16383?!m&&(m=s,f=(0|f)==(0|(g=r<<1|(p=Q)>>>31))&n>>>0<(_=p<<1)>>>0|f>>>0>>0,_=65535&t,g=a<<1|(n=h)>>>31,(a=(r=(0|(t=a=n<<1|r>>>31))==(0|G)&(0|(r=g))==(0|P)?f:(0|P)==(0|r)&G>>>0>>0|P>>>0>>0)+o|0)>>>0>>0&&(m=m+1|0),r=a,65536&(i=_=(t=i+((0|s)==(0|(a=m))&(t=r)>>>0>>0|m>>>0>>0)|0)>>>0>>0?_+1|0:_))?(S|=t,M|=i):a=r=0:(d=s,f=(0|f)==(0|(_=r<<1|(p=Q)>>>31))&n>>>0<=(p<<=1)>>>0|f>>>0<_>>>0,_=a<<1|(n=h)>>>31,(a=(r=(0|(a=n<<1|r>>>31))==(0|G)&(0|_)==(0|P)?f:(0|P)==(0|_)&G>>>0<=a>>>0|P>>>0<_>>>0)+o|0)>>>0>>0&&(d=d+1|0),r=a,i=((0|s)==(0|(a=d))&r>>>0>>0|d>>>0>>0)+(n=i)|0,d=m<<16|(t&=65535),S|=i,M|=i>>>0>>0?d+1|0:d))}return P2[e>>2]=r,P2[e+4>>2]=a,P2[e+8>>2]=S,P2[e+12>>2]=M,void(R2=192+l|0)}P2[e>>2]=0,P2[e+4>>2]=0,P2[e+8>>2]=(r=!(i|n|t|f))?0:S,P2[e+12>>2]=r?2147450880:M,R2=192+l|0}function oe(e,r,a,i,t,n,f,o,s){var c,u,b,A=0,k=0,l=0,_=0,d=0,m=0,g=0,p=0,w=0,h=0;R2=b=R2-128|0;e:if(E2(n,f,o,s,0,0,0,0)&&(A=((e,r,a,i)=>{var t=0,n=65535&i;r:{if(32767!=(0|(i=i>>>16&32767))){if(t=4,i)break r;return e|a|r|n?3:2}t=!(e|a|r|n)}return t})(n,f,o,s),32767!=(0|(d=32767&(h=t>>>16|0))))&&A)if((0|E2(r,a,_=i,l=k=65535&t|d<<16,n,f,m=o,A=65535&s|(w=s>>>16&32767)<<16))<=0)s=E2(r,a,_,l,n,f,m,A)?(o=r,a):(u0(112+b|0,r,a,i,t,0,0,0,0),i=P2[120+b>>2],t=P2[124+b>>2],o=P2[112+b>>2],P2[116+b>>2]);else{if(o=d?(s=a,r):(u0(96+b|0,r,a,_,l,0,0,0,1081540608),l=o=P2[108+b>>2],_=P2[104+b>>2],d=(o>>>16|0)-120|0,s=P2[100+b>>2],P2[96+b>>2]),w||(u0(80+b|0,n,f,m,A,0,0,0,1081540608),A=n=P2[92+b>>2],m=P2[88+b>>2],w=(A>>>16|0)-120|0,f=P2[84+b>>2],n=P2[80+b>>2]),c=65535&A|65536,p=(m=_-(k=u=m)|0)-(A=(0|f)==(0|s)&o>>>0>>0|s>>>0>>0)|0,g=-1<(0|(k=((l=65535&l|65536)-(c+(_>>>0>>0)|0)|0)-(m>>>0>>0)|0))?1:0,m=o-n|0,A=s-((o>>>0>>0)+f|0)|0,(0|w)<(0|d)){for(;;){if(1&g){if(!(m|p|A|k)){u0(32+b|0,r,a,i,t,0,0,0,0),i=P2[40+b>>2],t=P2[44+b>>2],o=P2[32+b>>2],s=P2[36+b>>2];break e}p=(o=p)<<1,k=g=k<<1|o>>>31,o=A>>>31|(g=0)}else p=(A=s)>>>31|(k=0),m=o,g=l<<1|(o=_)>>>31,o<<=1;if(k=(k=(l=k|g)-(((s=_=o|p)>>>0<(o=u)>>>0)+c|0)|0)-((p=s-o|0)>>>0<(A=(0|f)==(0|(s=g=A<<1|(o=m)>>>31))&(o<<=1)>>>0>>0|s>>>0>>0)>>>0)|0,p=p-A|0,g=-1<(0|k)?1:0,m=o-n|0,A=s-((o>>>0>>0)+f|0)|0,!((0|w)<(0|(d=d+-1|0))))break}d=w}if(!g||(o=m)|(_=p)|(s=A)|(l=k)){if(65535==(0|l)|l>>>0<65535)for(;;)if(i=s>>>31|0,d=d+-1|(r=0),k=s<<1|o>>>31,o<<=1,s=k,!(65536==(0|(l=r|=g=l<<1|(a=_)>>>31))&(_=a<<1|i)>>>0<0|r>>>0<65536))break;r=32768&h,(0|d)<=0?(u0(b+64|0,o,s,_,65535&l|(r|d+120)<<16,0,0,0,1065811968),i=P2[72+b>>2],t=P2[76+b>>2],o=P2[64+b>>2],s=P2[68+b>>2]):(i=_,t=65535&l|(r|d)<<16)}else u0(48+b|0,r,a,i,t,0,0,0,0),i=P2[56+b>>2],t=P2[60+b>>2],o=P2[48+b>>2],s=P2[52+b>>2]}else u0(16+b|0,r,a,i,t,n,f,o,s),fe(b,t=P2[16+b>>2],i=P2[20+b>>2],a=P2[24+b>>2],r=P2[28+b>>2],t,i,a,r),i=P2[8+b>>2],t=P2[12+b>>2],o=P2[b>>2],s=P2[4+b>>2];P2[e>>2]=o,P2[e+4>>2]=s,P2[e+8>>2]=i,P2[e+12>>2]=t,R2=128+b|0}function se(N,e){var r,G,a,i=0,t=0,n=0,V=0,Y=0,R=0;for(R2=a=R2-48|0,r=e+4|0,V=P2[2644],G=P2[2641];;)if(!(32==(0|(i=(i=P2[e+4>>2])>>>0>2]?(P2[r>>2]=i+1,O2[0|i]):c0(e)))|i+-9>>>0<5))break;n=1;e:{r:switch(i+-43|0){case 0:case 2:break r;default:break e}n=45==(0|i)?-1:1,(i=P2[e+4>>2])>>>0>2]?(P2[r>>2]=i+1,i=O2[0|i]):i=c0(e)}e:{r:{a:{for(;;){if(s0[t+10484|0]!=(32|i))break;if(6>>0||(i=(i=P2[e+4>>2])>>>0>2]?(P2[r>>2]=i+1,O2[0|i]):c0(e)),8==(0|(t=t+1|0)))break a}if(3!=(0|t)){if(8==(0|t))break a;if(t>>>0<4)break r;if(8==(0|t))break a}if((e=P2[e+104>>2])&&(P2[r>>2]=P2[r>>2]+-1),!(t>>>0<4))for(;;)if(e&&(P2[r>>2]=P2[r>>2]+-1),!(3<(t=t+-1|0)>>>0))break}h2(a,V2(V2(0|n)*V2(A0))),n=P2[8+a>>2],i=P2[12+a>>2],Y=P2[a>>2],R=P2[4+a>>2];break e}r:{a:{i:if(!t){for(t=0;;){if(s0[t+10493|0]!=(32|i))break i;if(1>>0||(i=(i=P2[e+4>>2])>>>0>2]?(P2[r>>2]=i+1,O2[0|i]):c0(e)),3==(0|(t=t+1|0)))break}break a}i:switch(0|t){case 0:if(48==(0|i)){if(88==(-33&(t=(t=P2[e+4>>2])>>>0>2]?(P2[r>>2]=t+1,O2[0|t]):c0(e)))){var T=16+a|0,f=e,o=G,s=V,c=n,u=0,b=0,A=0,k=0,l=0,_=0,d=0,m=0,g=0,U=0,x=0,z=0,j=0,H=0,K=0,W=0,J=0,X=0,Z=0,q=0;R2=u=R2-432|0,A=(b=P2[f+4>>2])>>>0>2]?(P2[f+4>>2]=b+1,O2[0|b]):c0(f);t:{n:{for(;;){if(48!=(0|A)){if(46!=(0|A))break t;if((b=P2[f+4>>2])>>>0>=S2[f+104>>2])break;P2[f+4>>2]=b+1,A=O2[0|b];break n}b=P2[f+4>>2],A=b>>>0>2]?(P2[f+4>>2]=b+1,O2[0|b]):c0(f),J=1}A=c0(f)}if(W=1,48==(0|A)){for(;;)if(b=P2[f+4>>2],A=b>>>0>2]?(P2[f+4>>2]=b+1,O2[0|b]):c0(f),g=g+-1|0,-1!=(0|(j=j+-1|0))&&(g=g+1|0),48!=(0|A))break;J=1}}for(m=1073676288,b=0;;){t:{X=32|A;n:{if(!((Z=A+-48|0)>>>0<10)){if(5>>0&&46!=(0|A))break t;if(46==(0|A)){if(W)break t;W=1,j=l,g=b;break n}}A=57<(0|A)?X-87|0:Z,(0|b)<0||(0|b)<=0&&!(7>>0)?U=A+(U<<4)|0:(0|b)<0||(0|b)<=0&&!(28>>0)?(v2(48+u|0,A),u0(32+u|0,H,K,k,m,0,0,0,1073414144),H=P2[32+u>>2],K=P2[36+u>>2],k=P2[40+u>>2],m=P2[44+u>>2],u0(16+u|0,H,K,k,m,P2[48+u>>2],P2[52+u>>2],P2[56+u>>2],P2[60+u>>2]),y2(u,_,d,x,z,P2[16+u>>2],P2[20+u>>2],P2[24+u>>2],P2[28+u>>2]),x=P2[8+u>>2],z=P2[12+u>>2],_=P2[u>>2],d=P2[4+u>>2]):!A|q||(u0(80+u|0,H,K,k,m,0,0,0,1073610752),y2(u+64|0,_,d,x,z,P2[80+u>>2],P2[84+u>>2],P2[88+u>>2],P2[92+u>>2]),x=P2[72+u>>2],z=P2[76+u>>2],q=1,_=P2[64+u>>2],d=P2[68+u>>2]),(l=l+1|0)>>>0<1&&(b=b+1|0),J=1}A=(A=P2[f+4>>2])>>>0>2]?(P2[f+4>>2]=A+1,O2[0|A]):c0(f);continue}break}if(J){if((0|b)<0||(0|b)<=0&&!(7>>0))for(k=l,m=b;;)if(U<<=4,!(8!=(0|(k=k+1|0))|(m=k>>>0<1?m+1|0:m)))break;if(80==(-33&A)&&(k=ce(f))|-2147483648!=(0|(m=A=T2))||(m=k=0,P2[f+104>>2]&&(P2[f+4>>2]=P2[f+4>>2]+-1)),U)if(b=(W?g:b)<<2|(f=W?j:l)>>>30,g=(f=k+(f<<2)|0)+-32|0,b=b+m|0,f=(f>>>0>>0?b+1|0:b)+-1|0,0<(0|(b=(l=g)>>>0<4294967264?f+1|0:f))||0<=(0|b)&&!(l>>>0<=0-s>>>0))P2[2896]=68,v2(160+u|0,c),u0(144+u|0,P2[160+u>>2],P2[164+u>>2],P2[168+u>>2],P2[172+u>>2],-1,-1,-1,2147418111),u0(128+u|0,P2[144+u>>2],P2[148+u>>2],P2[152+u>>2],P2[156+u>>2],-1,-1,-1,2147418111),_=P2[128+u>>2],d=P2[132+u>>2],o=P2[136+u>>2],f=P2[140+u>>2];else if(A=l>>>0<(f=s+-226|0)>>>0?0:1,(0|(f>>=31))<(0|b)||(0|f)<=(0|b)&&A){if(-1<(0|U))for(;;)if(y2(416+u|0,_,d,x,z,0,0,0,-1073807360),f=F2(_,d,x,z,1073610752),y2(400+u|0,_,d,x,z,(k=(0|f)<0)?_:P2[416+u>>2],k?d:P2[420+u>>2],k?x:P2[424+u>>2],k?z:P2[428+u>>2]),b=b+-1|0,-1!=(0|(l=l+-1|0))&&(b=b+1|0),x=P2[408+u>>2],z=P2[412+u>>2],_=P2[400+u>>2],d=P2[404+u>>2],!(-1<(0|(U=U<<1|-1<(0|f)))))break;m=(A=o)>>>0<=(k=f=32+(l-s|0)|0)>>>0?0:1,o=b-((s>>31)+(l>>>0>>0)|0)|0,o=113<=(0|(f=(0|(f=f>>>0<32?o+1|0:o))<0||(0|f)<=0&&m?0<(0|k)?k:0:A))?(v2(384+u|0,c),j=P2[392+u>>2],g=P2[396+u>>2],H=P2[384+u>>2],K=P2[388+u>>2],s=c=b=0):(C2(352+u|0,l2(1,144-f|0)),v2(336+u|0,c),H=P2[336+u>>2],K=P2[340+u>>2],j=P2[344+u>>2],g=P2[348+u>>2],B2(368+u|0,P2[352+u>>2],P2[356+u>>2],P2[360+u>>2],P2[364+u>>2],0,0,0,g),b=P2[376+u>>2],c=P2[380+u>>2],s=P2[372+u>>2],P2[368+u>>2]),f=!(1&U)&0!=(0|E2(_,d,x,z,0,0,0,0))&(0|f)<32,D2(320+u|0,f+U|0),u0(304+u|0,H,K,j,g,P2[320+u>>2],P2[324+u>>2],P2[328+u>>2],P2[332+u>>2]),y2(272+u|0,P2[304+u>>2],P2[308+u>>2],P2[312+u>>2],P2[316+u>>2],o,s,b,c),u0(288+u|0,f?0:_,f?0:d,f?0:x,f?0:z,H,K,j,g),y2(256+u|0,P2[288+u>>2],P2[292+u>>2],P2[296+u>>2],P2[300+u>>2],P2[272+u>>2],P2[276+u>>2],P2[280+u>>2],P2[284+u>>2]),L2(240+u|0,P2[256+u>>2],P2[260+u>>2],P2[264+u>>2],P2[268+u>>2],o,s,b,c),f=P2[240+u>>2],o=P2[244+u>>2],s=P2[248+u>>2],c=P2[252+u>>2],E2(f,o,s,c,0,0,0,0)||(P2[2896]=68),I2(224+u|0,f,o,s,c,l),_=P2[224+u>>2],d=P2[228+u>>2],o=P2[232+u>>2],f=P2[236+u>>2]}else P2[2896]=68,v2(208+u|0,c),u0(192+u|0,P2[208+u>>2],P2[212+u>>2],P2[216+u>>2],P2[220+u>>2],0,0,0,65536),u0(176+u|0,P2[192+u>>2],P2[196+u>>2],P2[200+u>>2],P2[204+u>>2],0,0,0,65536),_=P2[176+u>>2],d=P2[180+u>>2],o=P2[184+u>>2],f=P2[188+u>>2];else C2(112+u|0,0*(0|c)),_=P2[112+u>>2],d=P2[116+u>>2],o=P2[120+u>>2],f=P2[124+u>>2]}else P2[f+104>>2]&&(o=P2[f+4>>2],P2[f+4>>2]=o+-1,P2[f+4>>2]=o+-2,W)&&(P2[f+4>>2]=o+-3),C2(96+u|0,0*(0|c)),_=P2[96+u>>2],d=P2[100+u>>2],o=P2[104+u>>2],f=P2[108+u>>2];P2[T>>2]=_,P2[T+4>>2]=d,P2[T+8>>2]=o,P2[T+12>>2]=f,R2=432+u|0,n=P2[24+a>>2],i=P2[28+a>>2],Y=P2[16+a>>2],R=P2[20+a>>2];break e}P2[e+104>>2]&&(P2[r>>2]=P2[r>>2]+-1)}var s=32+a|0,p=e,w=i,h=G,$=V,e0=n,v=0,y=0,C=0,E=0,F=0,B=0,D=0,L=0,I=0,M=0,Q=0,P=0,O=0,S=0,r0=0,a0=0,i0=0,t0=0,n0=0,f0=0,o0=0;R2=v=R2-8976|0,f0=0-(i0=h+$|0)|0;t:{n:{for(;;){if(48!=(0|w)){if(46!=(0|w))break t;if((w=P2[p+4>>2])>>>0>=S2[p+104>>2])break;P2[p+4>>2]=w+1,w=O2[0|w];break n}w=(w=P2[p+4>>2])>>>0>2]?(E=1,P2[p+4>>2]=w+1,O2[0|w]):(E=1,c0(p))}w=c0(p)}if(I=1,48==(0|w)){for(;;)if(w=(w=P2[p+4>>2])>>>0>2]?(P2[p+4>>2]=w+1,O2[0|w]):c0(p),y=y+-1|0,-1!=(0|(C=C+-1|0))&&(y=y+1|0),48!=(0|w))break;E=1}}P2[784+v>>2]=0;t:{n:{f:{o:{s:{if((D=46==(0|w))|(L=w+-48|0)>>>0<=9)for(;;){c:{if(1&D){if(!I){C=F,y=B,I=1;break c}E=!E;break s}(F=F+1|0)>>>0<1&&(B=B+1|0),(0|M)<=2044?(r0=48==(0|w)?r0:F,P2[(E=(784+v|0)+(M<<2)|0)>>2]=P?(G2(P2[E>>2],10)+w|0)-48|0:L,P=(w=9==(0|(L=P+(E=1)|0)))?0:L,M=w+M|0):48!=(0|w)&&(P2[8960+v>>2]=1|P2[8960+v>>2],r0=18396)}if(w=(w=P2[p+4>>2])>>>0>2]?(P2[p+4>>2]=w+1,O2[0|w]):c0(p),!((D=46==(0|w))|(L=w+-48|0)>>>0<10))break}if(C=I?C:F,y=I?y:B,!(!E|69!=(-33&w))){if((D=ce(p))|-2147483648!=(0|(Q=w=T2))||(Q=D=0,P2[p+104>>2]&&(P2[p+4>>2]=P2[p+4>>2]+-1)),!E)break f;y=y+Q|0,(C=C+D|0)>>>0>>0&&(y=y+1|0);break n}if(E=!E,(0|w)<0)break o}P2[p+104>>2]&&(P2[p+4>>2]=P2[p+4>>2]+-1)}if(!E)break n}P2[2896]=28,B=F=0,w2(p),p=w=0;break t}if(p=P2[784+v>>2])if((0|C)!=(0|F)|(0|y)!=(0|B)|(!(0<(0|B)||0<=(0|B)&&!(F>>>0<=9))?0:1)|(p>>>h|0?(0|h)<=30:0))if(0<(0|y)||0<=(0|y)&&!(C>>>0<=(0|$)/-2>>>0))P2[2896]=68,v2(96+v|0,e0),u0(80+v|0,P2[96+v>>2],P2[100+v>>2],P2[104+v>>2],P2[108+v>>2],-1,-1,-1,2147418111),u0(v+64|0,P2[80+v>>2],P2[84+v>>2],P2[88+v>>2],P2[92+v>>2],-1,-1,-1,2147418111),F=P2[64+v>>2],B=P2[68+v>>2],w=P2[72+v>>2],p=P2[76+v>>2];else if(w=(p=$+-226|0)>>>0<=C>>>0?0:1,(0|y)<(0|(p>>=31))||(0|y)<=(0|p)&&w)P2[2896]=68,v2(144+v|0,e0),u0(128+v|0,P2[144+v>>2],P2[148+v>>2],P2[152+v>>2],P2[156+v>>2],0,0,0,65536),u0(112+v|0,P2[128+v>>2],P2[132+v>>2],P2[136+v>>2],P2[140+v>>2],0,0,0,65536),F=P2[112+v>>2],B=P2[116+v>>2],w=P2[120+v>>2],p=P2[124+v>>2];else{if(P){if((0|P)<=8){for(p=P2[(w=(784+v|0)+(M<<2)|0)>>2];;)if(p=G2(p,10),9==(0|(P=P+1|0)))break;P2[w>>2]=p}M=M+1|0}if(!((0|(I=C))<(0|r0)|9<=(0|r0)|17<(0|C))){if(9==(0|I)){v2(192+v|0,e0),D2(176+v|0,P2[784+v>>2]),u0(160+v|0,P2[192+v>>2],P2[196+v>>2],P2[200+v>>2],P2[204+v>>2],P2[176+v>>2],P2[180+v>>2],P2[184+v>>2],P2[188+v>>2]),F=P2[160+v>>2],B=P2[164+v>>2],w=P2[168+v>>2],p=P2[172+v>>2];break t}if((0|I)<=8){v2(272+v|0,e0),D2(256+v|0,P2[784+v>>2]),u0(240+v|0,P2[272+v>>2],P2[276+v>>2],P2[280+v>>2],P2[284+v>>2],P2[256+v>>2],P2[260+v>>2],P2[264+v>>2],P2[268+v>>2]),v2(224+v|0,P2[10560+(0-I<<2)>>2]),fe(208+v|0,P2[240+v>>2],P2[244+v>>2],P2[248+v>>2],P2[252+v>>2],P2[224+v>>2],P2[228+v>>2],P2[232+v>>2],P2[236+v>>2]),F=P2[208+v>>2],B=P2[212+v>>2],w=P2[216+v>>2],p=P2[220+v>>2];break t}if(p=27+(G2(I,-3)+h|0)|0,!((w=P2[784+v>>2])>>>p|0&&(0|p)<=30)){v2(352+v|0,e0),D2(336+v|0,w),u0(320+v|0,P2[352+v>>2],P2[356+v>>2],P2[360+v>>2],P2[364+v>>2],P2[336+v>>2],P2[340+v>>2],P2[344+v>>2],P2[348+v>>2]),v2(304+v|0,P2[10488+(I<<2)>>2]),u0(288+v|0,P2[320+v>>2],P2[324+v>>2],P2[328+v>>2],P2[332+v>>2],P2[304+v>>2],P2[308+v>>2],P2[312+v>>2],P2[316+v>>2]),F=P2[288+v>>2],B=P2[292+v>>2],w=P2[296+v>>2],p=P2[300+v>>2];break t}}for(;;)if(P2[(784+v|0)+((M=(w=M)+-1|0)<<2)>>2])break;if(p=((P=0)|I)%9|0){if(L=-1<(0|I)?p:p+9|0,w){for(C=P2[10560+(0-L<<2)>>2],F=1e9/(0|C)|0,E=p=D=0;;)if(M=P2[(B=(784+v|0)+(p<<2)|0)>>2],y=D+(Q=(M>>>0)/(C>>>0)|0)|0,P2[B>>2]=y,E=(y=!y&(0|p)==(0|E))?E+1&2047:E,I=y?I+-9|0:I,D=G2(F,M-G2(C,Q)|0),(0|w)==(0|(p=p+1|0)))break;D&&(P2[(784+v|0)+(w<<2)>>2]=D,w=w+1|0)}else w=E=0;I=9+(I-L|0)|0}else E=0;for(;;){B=(784+v|0)+(E<<2)|0;n:{for(;;){if(36!=(0|I)|10384593<=S2[B>>2]&&36<=(0|I))break n;for(M=w+2047|0,D=0,L=w;;)if(w=L,p=P2[(L=(784+v|0)+((F=2047&M)<<2)|0)>>2],y=p>>>3|0,!(y=(C=(p<<=29)+D|0)>>>0

>>0?y+1|0:y)&C>>>(p=0)<1000000001|y>>>0<0||(p=he(C,y,1e9),C=C-b0(p,T2,1e9,0)|0),D=p,P2[L>>2]=C,L=(0|F)!=(w+-1&2047)||(0|E)==(0|F)||C?w:F,M=F+-1|0,(0|E)==(0|F))break;if(P=P+-29|0,D)break}(0|L)==(0|(E=E+-1&2047))&&(w=L+-1&2047,P2[(p=(784+v|0)+((L+2046&2047)<<2)|0)>>2]=P2[p>>2]|P2[(784+v|0)+(w<<2)>>2]),I=I+9|0,P2[(784+v|0)+(E<<2)>>2]=D;continue}break}n:{f:for(;;){for(C=w+1&2047,F=(784+v|0)+((w+-1&2047)<<2)|0;;){y=45<(0|I)?9:1;o:{for(;;){L=E,p=0;s:{for(;;){if((0|(E=p+L&2047))!=(0|w)&&(E=P2[(784+v|0)+(E<<2)>>2],B=P2[10512+(p<<2)>>2],!(E>>>0>>0))){if(B>>>0>>0)break s;if(4!=(0|(p=p+1|0)))continue}break}if(36==(0|I)){for(B=F=p=y=C=0;;)if((0|(E=p+L&2047))==(0|w)&&(P2[780+(((w=w+1&2047)<<2)+v|0)>>2]=0),u0(768+v|0,C,y,F,B,0,0,1342177280,1075633366),D2(752+v|0,P2[(784+v|0)+(E<<2)>>2]),y2(736+v|0,P2[768+v>>2],P2[772+v>>2],P2[776+v>>2],P2[780+v>>2],P2[752+v>>2],P2[756+v>>2],P2[760+v>>2],P2[764+v>>2]),F=P2[744+v>>2],B=P2[748+v>>2],C=P2[736+v>>2],y=P2[740+v>>2],4==(0|(p=p+1|0)))break;if(v2(720+v|0,e0),u0(704+v|0,C,y,F,B,P2[720+v>>2],P2[724+v>>2],P2[728+v>>2],P2[732+v>>2]),F=P2[712+v>>2],B=P2[716+v>>2],y=C=0,D=P2[704+v>>2],Q=P2[708+v>>2],(0|(p=(r0=(0|($=(t0=P+113|0)-$|0))<(0|h))?0<(0|$)?$:0:h))<=112)break o;h=E=M=I=0;break n}}if(P=y+P|0,(0|(E=w))!=(0|L))break}for(B=1e9>>>y|0,D=-1<>2],p=p+(Q>>>y|0)|0,P2[M>>2]=p,E=(p=!p&(0|E)==(0|L))?E+1&2047:E,I=p?I+-9|0:I,p=G2(B,D&Q),(0|(L=L+1&2047))==(0|w))break;if(!p)continue;if((0|C)!=(0|E)){P2[(784+v|0)+(w<<2)>>2]=p,w=C;continue f}P2[F>>2]=1|P2[F>>2],E=C;continue}break}break}C2(656+v|0,l2(1,225-p|0)),B2(688+v|0,P2[656+v>>2],P2[660+v>>2],P2[664+v>>2],P2[668+v>>2],0,0,0,B),E=P2[696+v>>2],h=P2[700+v>>2],I=P2[688+v>>2],M=P2[692+v>>2],C2(640+v|0,l2(1,113-p|0)),oe(672+v|0,D,Q,F,B,P2[640+v>>2],P2[644+v>>2],P2[648+v>>2],P2[652+v>>2]),C=P2[672+v>>2],y=P2[676+v>>2],O=P2[680+v>>2],S=P2[684+v>>2],L2(624+v|0,D,Q,F,B,C,y,O,S),y2(608+v|0,I,M,E,h,P2[624+v>>2],P2[628+v>>2],P2[632+v>>2],P2[636+v>>2]),F=P2[616+v>>2],B=P2[620+v>>2],D=P2[608+v>>2],Q=P2[612+v>>2]}(0|(a0=L+4&2047))==(0|w)||((a0=P2[(784+v|0)+(a0<<2)>>2])>>>0<=499999999?(L+5&2047)==(0|w)&&!a0||(C2(496+v|0,.25*(0|e0)),y2(480+v|0,C,y,O,S,P2[496+v>>2],P2[500+v>>2],P2[504+v>>2],P2[508+v>>2]),O=P2[488+v>>2],S=P2[492+v>>2],C=P2[480+v>>2],y=P2[484+v>>2]):y=5e8!=(0|a0)?(C2(592+v|0,.75*(0|e0)),y2(576+v|0,C,y,O,S,P2[592+v>>2],P2[596+v>>2],P2[600+v>>2],P2[604+v>>2]),O=P2[584+v>>2],S=P2[588+v>>2],C=P2[576+v>>2],P2[580+v>>2]):(n0=0|e0,(L+5&2047)==(0|w)?(C2(528+v|0,.5*n0),y2(512+v|0,C,y,O,S,P2[528+v>>2],P2[532+v>>2],P2[536+v>>2],P2[540+v>>2]),O=P2[520+v>>2],S=P2[524+v>>2],C=P2[512+v>>2],P2[516+v>>2]):(C2(560+v|0,.75*n0),y2(544+v|0,C,y,O,S,P2[560+v>>2],P2[564+v>>2],P2[568+v>>2],P2[572+v>>2]),O=P2[552+v>>2],S=P2[556+v>>2],C=P2[544+v>>2],P2[548+v>>2])),111<(0|p))||(oe(464+v|0,C,y,O,S,0,0,0,1073676288),E2(P2[464+v>>2],P2[468+v>>2],P2[472+v>>2],P2[476+v>>2],0,0,0,0))||(y2(448+v|0,C,y,O,S,0,0,0,1073676288),O=P2[456+v>>2],S=P2[460+v>>2],C=P2[448+v>>2],y=P2[452+v>>2]),y2(432+v|0,D,Q,F,B,C,y,O,S),L2(416+v|0,P2[432+v>>2],P2[436+v>>2],P2[440+v>>2],P2[444+v>>2],I,M,E,h),F=P2[424+v>>2],B=P2[428+v>>2],D=P2[416+v>>2],Q=P2[420+v>>2],(2147483647&t0)<=(-2-i0|0)||(P2[(w=400+v|0)+8>>2]=F,P2[w+12>>2]=2147483647&B,P2[w>>2]=D,P2[w+4>>2]=Q,u0(384+v|0,D,Q,F,B,0,0,0,1073610752),h=F2(P2[400+v>>2],P2[404+v>>2],P2[408+v>>2],P2[412+v>>2],1081081856),F=(w=(0|h)<0)?F:P2[392+v>>2],B=w?B:P2[396+v>>2],D=w?D:P2[384+v>>2],Q=w?Q:P2[388+v>>2],P=(-1<(0|h))+P|0,o0=!(r0&(w|(0|p)!=(0|$))&0!=(0|E2(C,y,O,S,0,0,0,0))),(P+110|0)<=(0|f0)&&o0)||(P2[2896]=68),I2(368+v|0,D,Q,F,B,P),F=P2[368+v>>2],B=P2[372+v>>2],w=P2[376+v>>2],p=P2[380+v>>2]}else v2(48+v|0,e0),D2(32+v|0,p),u0(16+v|0,P2[48+v>>2],P2[52+v>>2],P2[56+v>>2],P2[60+v>>2],P2[32+v>>2],P2[36+v>>2],P2[40+v>>2],P2[44+v>>2]),F=P2[16+v>>2],B=P2[20+v>>2],w=P2[24+v>>2],p=P2[28+v>>2];else C2(v,0*(0|e0)),F=P2[v>>2],B=P2[4+v>>2],w=P2[8+v>>2],p=P2[12+v>>2]}P2[s>>2]=F,P2[s+4>>2]=B,P2[s+8>>2]=w,P2[s+12>>2]=p,R2=8976+v|0,n=P2[40+a>>2],i=P2[44+a>>2],Y=P2[32+a>>2],R=P2[36+a>>2];break e;case 3:break a;default:break i}P2[e+104>>2]&&(P2[r>>2]=P2[r>>2]+-1);break r}if(40!=(0|(i=(t=P2[e+4>>2])>>>0>2]?(P2[r>>2]=t+1,O2[0|t]):c0(e)))){if(n=0,i=2147450880,!P2[e+104>>2])break e;P2[r>>2]=P2[r>>2]+-1;break e}for(t=1;;){if(26<=(V=(i=P2[e+4>>2])>>>0>2]?(P2[r>>2]=i+1,O2[0|i]):c0(e))+-97>>>0&&!(V+-48>>>0<10|V+-65>>>0<26|95==(0|V)))break;t=t+1|0}if(i=2147450880,41==((n=0)|V))break e;if((e=P2[e+104>>2])&&(P2[r>>2]=P2[r>>2]+-1),!t)break e;for(;;)if(t=t+-1|0,e&&(P2[r>>2]=P2[r>>2]+-1),!t)break;break e}P2[2896]=28,w2(e),i=n=0}P2[N>>2]=Y,P2[N+4>>2]=R,P2[N+8>>2]=n,P2[N+12>>2]=i,R2=48+a|0}function ce(e){var r=0,a=0,i=0,t=0,n=0;e:{r:{a:switch((a=(i=P2[e+4>>2])>>>0>2]?(P2[e+4>>2]=i+1,O2[0|i]):c0(e))+-43|0){case 0:case 2:break r;default:break a}r=a+-48|0;break e}n=45==(0|a),(r=(a=(i=P2[e+4>>2])>>>0>2]?(P2[e+4>>2]=i+1,O2[0|i]):c0(e))+-48|0)>>>0<10|!P2[e+104>>2]||(P2[e+4>>2]=P2[e+4>>2]+-1)}if(r>>>0<10){for(r=0;;)if(r=G2(r,10)+a|0,t=(a=(i=P2[e+4>>2])>>>0>2]?(P2[e+4>>2]=i+1,O2[0|i]):c0(e))+-48|0,!((0|(r=r+-48|0))<214748364&&t>>>0<=9))break;i=r,r>>=31;e:if(!(10<=t>>>0))for(;;){if(i=(r=b0(i,r,10,0))+a|0,a=T2,t=i>>>0>>0?a+1|0:a,a=(r=P2[e+4>>2])>>>0>2]?(P2[e+4>>2]=r+1,O2[0|r]):c0(e),r=t+-1|0,(i=i+-48|0)>>>0<4294967248&&(r=r+1|0),9<(t=a+-48|0)>>>0)break e;if(!((0|r)<21474836||(0|r)<=21474836&&!(2061584302<=i>>>0)))break}if(t>>>0<10)for(;;)if(!((a=(a=P2[e+4>>2])>>>0>2]?(P2[e+4>>2]=a+1,O2[0|a]):c0(e))+-48>>>0<10))break;P2[e+104>>2]&&(P2[e+4>>2]=P2[e+4>>2]+-1),e=i,i=n?0-e|0:e,r=n?0-(r+(0>>0)|0)|0:r}else if(i=0,r=-2147483648,P2[e+104>>2])return P2[e+4>>2]=P2[e+4>>2]+-1,T2=-2147483648,0;return T2=r,i}function ue(e){var r,a,i,t,n,f,o,s,c,u,b=0;return a=R2=u=R2-16|0,e=e,U2(16+(R2=f=R2-160|0)|0,144),P2[92+f>>2]=-1,P2[60+f>>2]=e,P2[24+f>>2]=-1,P2[20+f>>2]=e,w2(16+f|0),se(f,16+f|0),e=P2[8+f>>2],i=P2[12+f>>2],r=P2[4+f>>2],P2[a>>2]=P2[f>>2],P2[a+4>>2]=r,P2[a+8>>2]=e,P2[a+12>>2]=i,R2=160+f|0,r=P2[u>>2],e=P2[4+u>>2],a=P2[8+u>>2],i=P2[12+u>>2],R2=n=R2-32|(c=s=o=f=0),f=(c=f=2147483647&i)+-1006698496|0,o=f=(t=o=s=a)>>>0<0?f+1|0:f,f=c+-1140785152|0,(0|(f=s>>>0<0?f+1|0:f))==(0|o)&t>>>0>>0|o>>>0>>0?(f=i<<4|a>>>28,a=a<<4|e>>>28,134217728==(0|(s=e&=268435455))&1<=r>>>0|134217728>>0?(f=f+1073741824|0,(r=a+1|0)>>>0<1&&(f=f+1|0),o=r):(f=f-(((o=a)>>>0<0)+-1073741824|0)|0,r|134217728^s||((r=o+(1&o)|0)>>>0>>0&&(f=f+1|0),o=r))):(!s&2147418112==(0|c)?!(r|e):2147418112==(0|c)&s>>>0<0|c>>>0<2147418112)?(f=2146435072,1140785151>>(o=0)||(s=c>>>16|(f=0))>>>0<15249||(U(16+n|0,r,e,a,f=65535&i|65536,s+-15233|0),x(n,r,e,a,f,15361-s|0),a=P2[4+n>>2],r=P2[8+n>>2],f=P2[12+n>>2]<<4|r>>>28,o=r<<4|a>>>28,134217728==(0|(a=r=268435455&a))&1<=(e=P2[n>>2]|(0!=(P2[16+n>>2]|P2[24+n>>2])|0!=(P2[20+n>>2]|P2[28+n>>2])))>>>0|134217728>>0?((r=o+1|0)>>>0<1&&(f=f+1|0),o=r):e|134217728^a||((r=o+(1&o)|0)>>>0>>0&&(f=f+1|0),o=r))):(o=a<<4|e>>>28,f=524287&(f=i<<4|a>>>28)|2146959360),R2=32+n|0,d(0,0|o),d(1,-2147483648&i|f),b=+m(),R2=16+u|0,b}function be(e,r){var a=0,i=0,t=0,n=V2(0),f=V2(0),o=0,s=0,c=V2(0),u=0,b=0,a=P2[e>>2];if(1==P2[a>>2]){for(P2[a+40>>2]=0;;){e:{r:{a:{i:{t:{n:{f:{o:{s:{c:{u:{b:{A:{k:{if(!(b=8!=(0|(t=(u=Y0(r,59))?u-r|0:V0(r))))){if(A(10584,r,8))break k;P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=0;break e}l:switch(t+-6|0){case 1:break u;case 0:break b;case 20:break A;case 7:break l;default:break c}if(o=1,A(10593,r,13))break s;P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=1;break e}if(o=0,A(10607,r,8))break s;P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=2;break e}if(o=0,A(10616,r,26))break s;P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=3;break e}if(A(10643,r,6))break e;P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=4;break e}if(A(10650,r,7))break o;P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=5;break e}if(t>>>(o=0)<8)break f}if(A(10658,r,6))break n;if((f=V2(ue(r+6|0)))>V2(0)^1|f<=V2(.5)^1)break e;r=P2[e>>2],N2[48+((P2[r+40>>2]<<4)+r|0)>>2]=f,r=P2[e>>2],t=P2[r+40>>2],P2[r+40>>2]=t+1,P2[44+(r+(t<<4)|0)>>2]=6;break e}if(A(10665,r,7))break t;P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=7;break e}f:switch(t+-4|0){case 0:break f;case 1:break a;default:break e}if(A(10673,r,4))break e;P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=8;break e}if(!o)break i;if(A(10678,r,13))break i;P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=9;break e}if(A(10692,r,7))break e;P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=10;break e}if(9==(0|t)&&!A(10700,r,9)){P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=11;break e}if(!b){if(!A(10710,r,8)){P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=12;break e}if(A(10719,r,6))break e;break r}if(!A(10719,r,6))break r;if(t>>>0<16)break e;if(!A(10726,r,14)){if(s=ue(r+14|0),t=Y2(s)<2147483648?~~s:-2147483648,i=Y0(r,47),n=V2(.10000000149011612),i&&(a=i+1|0,n=V2(.9900000095367432),V2(ue(a))>2],a=P2[r+40>>2],(0|t)<=1){N2[48+((a<<4)+r|0)>>2]=f,r=P2[e>>2],t=P2[r+40>>2],P2[r+40>>2]=t+1,P2[44+(r+(t<<4)|0)>>2]=13;break e}if(31>>0)break e;for(c=V2(V2(V2(1)/V2(V2(1)-n))+V2(-1)),n=V2(c+V2(0|t)),i=0;;)if(N2[48+((a<<4)+r|0)>>2]=f,r=P2[e>>2],N2[52+((P2[r+40>>2]<<4)+r|0)>>2]=V2(0|i)/n,r=P2[e>>2],N2[56+((P2[r+40>>2]<<4)+r|0)>>2]=V2(c+V2(0|(i=i+1|0)))/n,r=P2[e>>2],o=P2[r+40>>2],P2[r+40>>2]=a=o+1|0,P2[44+((o<<4)+r|0)>>2]=14,(0|i)==(0|t))break;break e}if(t>>>0<17)break e;if(A(10741,r,15))break e;if(s=ue(r+15|0),t=Y2(s)<2147483648?~~s:-2147483648,f=V2(.20000000298023224),i=Y0(r,47),n=V2(.20000000298023224),i&&(a=i+1|0,n=V2(.9900000095367432),V2(ue(a))>2],a=P2[r+40>>2],(0|t)<=1){N2[48+((a<<4)+r|0)>>2]=f,r=P2[e>>2],t=P2[r+40>>2],P2[r+40>>2]=t+1,P2[44+(r+(t<<4)|0)>>2]=13;break e}if(31>>0)break e;for(c=V2(V2(V2(1)/V2(V2(1)-n))+V2(-1)),n=V2(c+V2(0|t)),i=0;;)if(N2[48+((a<<4)+r|0)>>2]=f,r=P2[e>>2],N2[52+((P2[r+40>>2]<<4)+r|0)>>2]=V2(0|i)/n,r=P2[e>>2],N2[56+((P2[r+40>>2]<<4)+r|0)>>2]=V2(c+V2(0|(i=i+1|0)))/n,r=P2[e>>2],o=P2[r+40>>2],P2[r+40>>2]=a=o+1|0,P2[44+((o<<4)+r|0)>>2]=15,(0|i)==(0|t))break;break e}if(A(10757,r,5))break e;P2[a+40>>2]=i+1,P2[44+((i<<4)+a|0)>>2]=16;break e}(f=V2(ue(r+6|0)))>=V2(0)^1|f<=V2(1)^1||(r=P2[e>>2],N2[48+((P2[r+40>>2]<<4)+r|0)>>2]=f,r=P2[e>>2],t=P2[r+40>>2],P2[r+40>>2]=t+1,P2[44+(r+(t<<4)|0)>>2]=13)}if(a=P2[e>>2],i=P2[a+40>>2],!u||(r=u+1|0,32==(0|i)))break}t=1,i||(P2[a+40>>2]=1,P2[a+44>>2]=13,P2[a+48>>2]=1056964608)}return t}function Ae(e){var r,a,i,t,n,f=0,o=0,s=0,c=0,u=0,b=0,A=0,k=0,l=0,_=0,d=0,m=0,g=0;R2=i=R2-32|0;e:if(e|=0){r:{a:switch(u=P2[e>>2],0|(f=P2[u>>2])){case 1:break e;case 0:break a;default:break r}o=P2[e+4>>2],P2[o+11848>>2]||(o=P2[o+7052>>2])&&(s=P2[u+36>>2],s=!ke(e,(0|(P2[u+36>>2]=o))!=(0|s),1),u=P2[e>>2])}if(P2[u+12>>2]&&D0((o=P2[e+4>>2])+6928|0,o+7060|0),u=e+4|0,f=P2[e+4>>2],P2[f+11848>>2])o=s;else{if(c=P2[e>>2],!P2[c>>2]){if(_=P2[f+7268>>2]){r:if(P2[f+7260>>2]){if(m=P2[f+6900>>2],d=P2[f+6896>>2],A=P2[(o=f+6920|0)>>2],k=P2[o+4>>2],2!=(0|Q2[_](e,0,0,P2[f+7288>>2]))){if(c2(i),o=P2[e>>2],c=P2[o+608>>2],b=P2[o+612>>2],o=P2[e+4>>2],b2(e,c,b,i,P2[o+7268>>2],P2[o+7264>>2],P2[o+7288>>2])){if(_=P2[1357]+P2[1356]|0,(o=(g=P2[1362]+(P2[1361]+(P2[1360]+(P2[1359]+(_+P2[1358]|0)|0)|0)|0)|0)+P2[1363]>>>3|0)+33>>>0>S2[12+i>>2]){P2[P2[e>>2]>>2]=2,u2(i);break r}if(l=O2[(c=f+6936|0)+4|0]|O2[c+5|0]<<8|(O2[c+6|0]<<16|O2[c+7|0]<<24),o=o+P2[8+i>>2]|0,c=O2[0|c]|O2[c+1|0]<<8|(O2[c+2|0]<<16|O2[c+3|0]<<24),s0[o+25|0]=c,s0[o+26|0]=c>>>8,s0[o+27|0]=c>>>16,s0[o+28|0]=c>>>24,s0[o+29|0]=l,s0[o+30|0]=l>>>8,s0[o+31|0]=l>>>16,s0[o+32|0]=l>>>24,c=O2[(f=f+6928|0)+4|0]|O2[f+5|0]<<8|(O2[f+6|0]<<16|O2[f+7|0]<<24),f=O2[0|f]|O2[f+1|0]<<8|(O2[f+2|0]<<16|O2[f+3|0]<<24),s0[o+17|0]=f,s0[o+18|0]=f>>>8,s0[o+19|0]=f>>>16,s0[o+20|0]=f>>>24,s0[o+21|0]=c,s0[o+22|0]=c>>>8,s0[o+23|0]=c>>>16,s0[o+24|0]=c>>>24,(o=g+-4>>>3|0)+22>>>0>S2[12+i>>2]){P2[P2[e>>2]>>2]=2,u2(i);break r}if(o=o+P2[8+i>>2]|0,s0[o+21|0]=A,s0[o+20|0]=(255&k)<<24|A>>>8,s0[o+19|0]=(65535&k)<<16|A>>>16,s0[o+18|0]=(16777215&k)<<8|A>>>24,s0[0|(o=o+17|0)]=240&O2[0|o]|15&k,(o=_>>>3|0)+23>>>0>S2[12+i>>2]){P2[P2[e>>2]>>2]=2,u2(i);break r}if(o=o+P2[8+i>>2]|0,s0[o+22|0]=m,s0[o+21|0]=m>>>8,s0[o+20|0]=m>>>16,s0[o+19|0]=d,s0[o+18|0]=d>>>8,s0[o+17|0]=d>>>16,o=P2[e>>2],c=P2[o+608>>2],f=P2[o+612>>2],o=P2[e+4>>2],o=A2(e,c,f,i,P2[o+7268>>2],P2[o+7276>>2],P2[o+7288>>2]),u2(i),!o)break r;if(!(o=P2[P2[u>>2]+7048>>2])|!P2[o>>2])break r;if(f=P2[e>>2],!(P2[f+616>>2]|P2[f+620>>2]))break r;if(o0(o),c2(i),o=P2[e>>2],c=P2[o+616>>2],f=P2[o+620>>2],o=P2[e+4>>2],b2(e,c,f,i,P2[o+7268>>2],P2[o+7264>>2],P2[o+7288>>2])){if(b=P2[u>>2],o=P2[b+7048>>2],f=P2[o>>2],P2[12+i>>2]!=(G2(f,18)+4|0)){P2[P2[e>>2]>>2]=2,u2(i);break r}if(f)for(f=P2[8+i>>2]+4|0,c=0;;)if(A=P2[o+4>>2]+G2(c,24)|0,k=P2[A>>2],o=P2[A+4>>2],l=P2[A+8>>2],b=P2[A+12>>2],A=P2[A+16>>2],s0[f+17|0]=A,s0[f+15|0]=l,s0[f+7|0]=k,s0[f+16|0]=A>>>8,s0[f+14|0]=(255&b)<<24|l>>>8,s0[f+13|0]=(65535&b)<<16|l>>>16,s0[f+12|0]=(16777215&b)<<8|l>>>24,s0[f+11|0]=b,s0[f+10|0]=b>>>8,s0[f+9|0]=b>>>16,s0[f+8|0]=b>>>24,s0[f+6|0]=(255&o)<<24|k>>>8,s0[f+5|0]=(65535&o)<<16|k>>>16,s0[f+4|0]=(16777215&o)<<8|k>>>24,s0[f+3|0]=o,s0[f+2|0]=o>>>8,s0[f+1|0]=o>>>16,s0[0|f]=o>>>24,f=f+18|0,b=P2[u>>2],o=P2[b+7048>>2],!((c=c+1|0)>>>0>2]))break;o=P2[e>>2],A2(e,P2[o+616>>2],P2[o+620>>2],i,P2[b+7268>>2],P2[b+7276>>2],P2[b+7288>>2])}}u2(i)}}else{m=P2[f+6912>>2],A=P2[f+6900>>2],k=P2[f+6896>>2],o=P2[(b=f+6920|0)>>2],b=P2[b+4>>2];a:{i:switch(a=e,l=P2[c+612>>2],d=P2[1357]+P2[1356]|0,c=(r=4+((g=P2[1362]+(P2[1361]+(P2[1360]+(P2[1359]+(d+P2[1358]|0)|0)|0)|0)|0)+P2[1363]>>>3|0)|0)+P2[c+608>>2]|0,0|Q2[_](a,c,l=c>>>0>>0?l+1|0:l,P2[f+7288>>2])){case 0:break a;case 1:break i;default:break r}P2[P2[e>>2]>>2]=5;break r}if(c=f+6928|0,f=P2[e+4>>2],Q2[P2[f+7276>>2]](e,c,16,0,0,P2[f+7288>>2]))P2[P2[e>>2]>>2]=5;else{s0[4+i|0]=o,s0[3+i|0]=(255&b)<<24|o>>>8,s0[2+i|0]=(65535&b)<<16|o>>>16,s0[1+i|0]=(16777215&b)<<8|o>>>24,s0[0|i]=240+(15&b|m<<4);a:{i:switch(f=P2[e>>2],c=(o=4+(g+-4>>>3|0)|0)+P2[f+608>>2]|0,f=P2[f+612>>2],f=c>>>0>>0?f+1|0:f,o=P2[e+4>>2],0|Q2[P2[o+7268>>2]](e,c,f,P2[o+7288>>2])){case 0:break a;case 1:break i;default:break r}P2[P2[e>>2]>>2]=5;break r}if(o=P2[e+4>>2],Q2[P2[o+7276>>2]](e,i,5,0,0,P2[o+7288>>2]))P2[P2[e>>2]>>2]=5;else{s0[5+i|0]=A,s0[4+i|0]=A>>>8,s0[3+i|0]=A>>>16,s0[2+i|0]=k,s0[1+i|0]=k>>>8,s0[0|i]=k>>>16;a:{i:switch(f=P2[e>>2],c=(o=4+(d>>>3|0)|0)+P2[f+608>>2]|0,f=P2[f+612>>2],f=c>>>0>>0?f+1|0:f,o=P2[e+4>>2],0|Q2[P2[o+7268>>2]](e,c,f,P2[o+7288>>2])){case 0:break a;case 1:break i;default:break r}P2[P2[e>>2]>>2]=5;break r}if(o=P2[e+4>>2],Q2[P2[o+7276>>2]](e,i,6,0,0,P2[o+7288>>2]))P2[P2[e>>2]>>2]=5;else if(!(!(o=P2[P2[u>>2]+7048>>2])|!P2[o>>2])&&(f=P2[e>>2],P2[f+616>>2]|P2[f+620>>2])){o0(o);a:{i:{t:switch(o=P2[e>>2],f=P2[o+616>>2]+4|0,o=P2[o+620>>2],c=f>>>0<4?o+1|0:o,o=P2[e+4>>2],0|Q2[P2[o+7268>>2]](e,f,c,P2[o+7288>>2])){case 1:break i;case 0:break t;default:break r}if(c=P2[u>>2],f=P2[c+7048>>2],!P2[f>>2])break r;b=0;break a}P2[P2[e>>2]>>2]=5;break r}for(;;){if(A=(k=G2(b,24))+P2[f+4>>2]|0,o=P2[A+4>>2],l=(A=P2[A>>2])<<24|A<<8&16711680,P2[i>>2]=-16777216&((255&o)<<24|A>>>8)|16711680&((16777215&o)<<8|A>>>24)|o>>>8&65280|o>>>24,P2[4+i>>2]=65280&(o<<24|A>>>8)|255&(o<<8|A>>>24)|l,A=k+P2[f+4>>2]|0,o=P2[A+12>>2],l=(A=P2[A+8>>2])<<24|A<<8&16711680,P2[8+i>>2]=-16777216&((255&o)<<24|A>>>8)|16711680&((16777215&o)<<8|A>>>24)|o>>>8&65280|o>>>24,P2[12+i>>2]=65280&(o<<24|A>>>8)|255&(o<<8|A>>>24)|l,o=C[16+(k+P2[f+4>>2]|0)>>1],p[16+i>>1]=(o<<24|o<<8&16711680)>>>16,Q2[P2[c+7276>>2]](e,i,18,0,0,P2[c+7288>>2]))break;if(c=P2[u>>2],f=P2[c+7048>>2],!((b=b+1|0)>>>0>2]))break r}P2[P2[e>>2]>>2]=5}}}}f=P2[e+4>>2],c=P2[e>>2],s=P2[c>>2]?1:s}(o=P2[f+7280>>2])&&(Q2[o](e,f+6872|0,P2[f+7288>>2]),c=P2[e>>2])}!P2[c+4>>2]||!(o=P2[P2[u>>2]+11752>>2])||T0(o)?o=s:(o=1,s||(P2[P2[e>>2]>>2]=4))}if(f=P2[u>>2],(s=P2[f+7296>>2])&&((0|s)!=P2[1896]&&(P0(s),f=P2[u>>2]),P2[f+7296>>2]=0),P2[f+7260>>2]&&l0(P2[e>>2]+640|0),f=P2[e>>2],(s=P2[f+600>>2])&&(z2(s),f=P2[e>>2],P2[f+600>>2]=0,P2[f+604>>2]=0),P2[f+24>>2])for(s=0;;)if(c=P2[u>>2],(b=P2[7328+(c+(f=s<<2)|0)>>2])&&(z2(b),P2[7328+(f+P2[u>>2]|0)>>2]=0,c=P2[u>>2]),(c=P2[7368+(c+f|0)>>2])&&(z2(c),P2[7368+(f+P2[u>>2]|0)>>2]=0),!((s=s+1|0)>>>0>2]+24>>2]))break;if(f=P2[u>>2],(s=P2[f+7360>>2])&&(z2(s),P2[P2[u>>2]+7360>>2]=0,f=P2[u>>2]),(s=P2[f+7400>>2])&&(z2(s),P2[P2[u>>2]+7400>>2]=0,f=P2[u>>2]),(s=P2[f+7364>>2])&&(z2(s),P2[P2[u>>2]+7364>>2]=0,f=P2[u>>2]),(s=P2[f+7404>>2])&&(z2(s),P2[P2[u>>2]+7404>>2]=0,f=P2[u>>2]),c=P2[e>>2],P2[c+40>>2])for(s=0;;)if((A=P2[7408+((b=s<<2)+f|0)>>2])&&(z2(A),P2[7408+(b+P2[e+4>>2]|0)>>2]=0,c=P2[e>>2],f=P2[e+4>>2]),!((s=s+1|0)>>>0>2]))break;if((s=P2[f+7536>>2])&&(z2(s),f=P2[e+4>>2],P2[f+7536>>2]=0,c=P2[e>>2]),P2[c+24>>2])for(c=0;;)if((b=P2[7540+((s=c<<3)+f|0)>>2])&&(z2(b),P2[7540+(s+P2[u>>2]|0)>>2]=0,f=P2[u>>2]),(b=P2[7544+(f+s|0)>>2])&&(z2(b),P2[7544+(s+P2[u>>2]|0)>>2]=0,f=P2[u>>2]),!((c=c+1|0)>>>0>2]+24>>2]))break;if((s=P2[f+7604>>2])&&(z2(s),P2[P2[u>>2]+7604>>2]=0,f=P2[u>>2]),(s=P2[f+7608>>2])&&(z2(s),P2[P2[u>>2]+7608>>2]=0,f=P2[u>>2]),(s=P2[f+7612>>2])&&(z2(s),P2[P2[u>>2]+7612>>2]=0,f=P2[u>>2]),(s=P2[f+7616>>2])&&(z2(s),P2[P2[u>>2]+7616>>2]=0,f=P2[u>>2]),(s=P2[f+7620>>2])&&(z2(s),f=P2[u>>2],P2[f+7620>>2]=0),(s=P2[f+7624>>2])&&(z2(s),f=P2[u>>2],P2[f+7624>>2]=0),s=P2[e>>2],!(!P2[s+4>>2]|!P2[s+24>>2]))for(u=0;;)if((b=P2[11764+((c=u<<2)+f|0)>>2])&&(z2(b),P2[11764+(c+P2[e+4>>2]|0)>>2]=0,f=P2[e+4>>2],s=P2[e>>2]),!((u=u+1|0)>>>0>2]))break;t=P2[f+6856>>2],(n=P2[t>>2])&&z2(n),P2[t+16>>2]=0,P2[t>>2]=0,P2[t+8>>2]=0,P2[t+12>>2]=0,s=P2[e>>2],P2[s+44>>2]=13,P2[s+48>>2]=1056964608,P2[s+36>>2]=0,P2[s+40>>2]=1,P2[s+28>>2]=16,P2[s+32>>2]=44100,P2[s+20>>2]=0,P2[s+24>>2]=2,P2[s+12>>2]=1,P2[s+16>>2]=0,P2[s+4>>2]=0,P2[s+8>>2]=1,s=P2[e>>2],P2[s+592>>2]=0,P2[s+596>>2]=0,P2[s+556>>2]=0,P2[s+560>>2]=0,P2[s+564>>2]=0,P2[s+568>>2]=0,P2[s+572>>2]=0,P2[s+576>>2]=0,P2[s+580>>2]=0,P2[s+584>>2]=0,P2[s+600>>2]=0,P2[s+604>>2]=0,f=P2[e+4>>2],P2[f+7248>>2]=0,P2[f+7252>>2]=0,P2[f+7048>>2]=0,P2[(u=f+7256|0)>>2]=0,P2[u+4>>2]=0,P2[(u=f+7264|0)>>2]=0,P2[u+4>>2]=0,P2[(u=f+7272|0)>>2]=0,P2[u+4>>2]=0,P2[(u=f+7280|0)>>2]=0,P2[u+4>>2]=0,P2[f+7288>>2]=0,o2(s+632|0),f=P2[e>>2],1==P2[f>>2]&&(P2[f+16>>2]=1,P2[f+20>>2]=0,be(e,10777),f=P2[e>>2],1==P2[f>>2])&&(P2[f+576>>2]=0,P2[f+580>>2]=5,P2[f+564>>2]=0,P2[f+568>>2]=0,P2[f+556>>2]=8,P2[f+560>>2]=0),o||(P2[f>>2]=1),f=!o}return R2=32+i|0,0|f}function ke(e,r,a){var i,t,n,f=0,o=0,s=0,c=0,u=0,b=0,A=0,k=0,l=0,_=0;R2=n=R2-48|0;e:if(o=P2[e>>2],P2[o+12>>2]&&(f=I0((f=P2[e+4>>2])+7060|0,f+4|0,P2[o+24>>2],P2[o+36>>2],P2[o+28>>2]+7>>>3|0),o=P2[e>>2],!f))P2[o>>2]=8,r=0;else{f=P2[o+576>>2],l=r?0:(r=(e=>{var r,a=0;r:{if(!(1&e)){for(;;)if(a=a+1|0,r=2&e,e=e>>>1|0,r)break;if(e=15,14>>0)break r}e=a}return e})(P2[o+36>>2]),o=P2[e>>2],r>>>0<(s=P2[o+580>>2])>>>0?r:s),u=P2[o+36>>2],P2[8+n>>2]=u,P2[12+n>>2]=P2[o+32>>2],r=P2[o+24>>2],P2[20+n>>2]=0,P2[16+n>>2]=r,r=P2[o+28>>2],P2[28+n>>2]=0,P2[24+n>>2]=r,s=P2[e+4>>2],P2[32+n>>2]=P2[s+7056>>2],i=f>>>0>>0?f:l;r:{a:{i:{t:{n:{f:{if(P2[o+16>>2]){if(!(!P2[o+20>>2]|!P2[s+6864>>2])&&(_=A=1,P2[s+6868>>2]))break f}else A=1;o:if(P2[o+24>>2])for(;;){if(_=(c<<2)+s|0,k=f=0,u){for(t=P2[_+4>>2],r=0;;)if(b=1&(f=P2[t+(r<<2)>>2]|f),u>>>0<=(r=r+1|0)>>>0||b)break;if(k=r=0,f&&(k=0,!b)){for(;;)if(r=r+1|0,b=2&f,f>>=1,b)break;if(k=b=0,r){for(;;)if(P2[(f=t+(b<<2)|0)>>2]=P2[f>>2]>>r,(0|(b=b+1|0))==(0|u))break;k=r}}}if(r=k,u=G2(c,584)+s|0,f=P2[o+28>>2],P2[u+624>>2]=r=f>>>0>>0?f:r,P2[u+916>>2]=r,P2[_+216>>2]=f-r,(f=P2[o+24>>2])>>>0<=(c=c+1|0)>>>0)break o;u=P2[o+36>>2]}else f=0;if(r=1,A)break n;u=P2[o+36>>2],_=0}if(b=P2[s+36>>2],c=f=0,u){for(r=0;;)if(A=1&(r=P2[(c<<2)+b>>2]|r),u>>>0<=(c=c+1|0)>>>0||A)break;if(c=0,!(A|!r)){for(;;)if(c=c+1|0,A=2&r,r>>=1,A)break;if(r=0,c){for(;;)if(P2[(A=(r<<2)+b|0)>>2]=P2[A>>2]>>c,(0|u)==(0|(r=r+1|0)))break}else c=0}}if(r=P2[o+28>>2],P2[s+5296>>2]=c=r>>>0>>0?r:c,P2[s+5588>>2]=c,P2[s+248>>2]=r-c,c=P2[o+36>>2]){for(u=P2[s+40>>2],r=0;;)if(A=1&(f=P2[u+(r<<2)>>2]|f),c>>>0<=(r=r+1|0)>>>0||A)break;if(r=0,f)if(A)f=0;else{for(;;)if(r=r+1|0,A=2&f,f>>=1,A)break;if(f=0,r){for(;;)if(P2[(A=u+(f<<2)|0)>>2]=P2[A>>2]>>r,(0|c)==(0|(f=f+1|0)))break;f=r}}else f=0}if(r=P2[o+28>>2],P2[s+5880>>2]=f=r>>>0>>0?r:f,P2[s+6172>>2]=f,P2[s+252>>2]=1+(r-f|0),_)break t;f=P2[o+24>>2],r=0}if(o=r,f)for(f=0;;)if(de(e,i,l,8+n|0,P2[(r=(f<<2)+s|0)+216>>2],P2[r+4>>2],(s=(f<<3)+s|0)+6176|0,s+6640|0,s+256|0,r+6768|0,r+6808|0),s=P2[e+4>>2],!((f=f+1|0)>>>0>2]+24>>2]))break;if(o)break i;b=P2[s+36>>2]}if(de(e,i,l,8+n|0,P2[s+248>>2],b,s+6240|0,s+6704|0,s+320|0,s+6800|0,s+6840|0),r=P2[e+4>>2],de(e,i,l,8+n|0,P2[r+252>>2],P2[r+40>>2],r+6248|0,r+6712|0,r+328|0,r+6804|0,r+6844|0),r=P2[e+4>>2],f=!P2[P2[e>>2]+20>>2]|!P2[r+6864>>2]?(o=(f=P2[r+6844>>2])+(s=P2[r+6808>>2])|0,s=s+(c=P2[r+6812>>2])|0,f+P2[r+6840>>2]>>>0<((o=(c=f+c|0)>>>0<(s=(u=o>>>0>>0)?o:s)>>>0)?c:s)>>>0?3:o?2:u):P2[r+6868>>2]?3:0,P2[(k=n)+20>>2]=f,!m2(8+n|0,P2[r+6856>>2])){P2[P2[e>>2]>>2]=7,r=0;break e}s=e,c=P2[8+n>>2];t:{n:switch(0|f){default:f=P2[e+4>>2],b=o=r=u=0;break t;case 0:r=(o=(f=P2[e+4>>2])+336|0)+G2(P2[f+6768>>2],292)|0,u=584+(o+G2(P2[f+6772>>2],292)|0)|0,o=P2[f+216>>2],b=P2[f+220>>2];break t;case 1:r=336+((f=P2[e+4>>2])+G2(P2[f+6768>>2],292)|0)|0,u=5592+(G2(P2[f+6804>>2],292)+f|0)|0,o=P2[f+216>>2],b=P2[f+252>>2];break t;case 2:u=920+((f=P2[e+4>>2])+G2(P2[f+6772>>2],292)|0)|0,r=5592+(G2(P2[f+6804>>2],292)+f|0)|0,o=P2[f+252>>2],b=P2[f+220>>2];break t;case 3:break n}r=(o=(f=P2[e+4>>2])+5008|0)+G2(P2[f+6800>>2],292)|0,u=584+(o+G2(P2[f+6804>>2],292)|0)|0,o=P2[f+248>>2],b=P2[f+252>>2]}if(!me(s,c,o,r,P2[f+6856>>2]))break a;if(!me(e,P2[8+n>>2],b,u,P2[P2[e+4>>2]+6856>>2]))break a;r=P2[e>>2];break r}if(f=m2(8+n|0,P2[s+6856>>2]),r=P2[e>>2],f){if(!P2[r+24>>2])break r;for(f=0;;){if(r=P2[e+4>>2],!me(e,P2[8+n>>2],P2[(s=r+(f<<2)|0)+216>>2],336+((r+G2(f,584)|0)+G2(P2[s+6768>>2],292)|0)|0,P2[r+6856>>2]))break a;if(r=P2[e>>2],!((f=f+1|0)>>>0>2]))break}break r}P2[r>>2]=7}r=0;break e}P2[r+20>>2]&&(r=P2[e+4>>2],f=P2[r+6864>>2]+1|0,P2[r+6864>>2]=f>>>0>2]?f:0),r=P2[e+4>>2],P2[r+6868>>2]=P2[20+n>>2],r=P2[r+6856>>2],k=1,(k=(f=7&P2[r+16>>2])?e2(r,8-f|0):k)&&q0(P2[P2[e+4>>2]+6856>>2],8+n|0)&&j2(P2[P2[e+4>>2]+6856>>2],C[8+n>>1],P2[1404])?(r=0,_e(e,P2[P2[e>>2]+36>>2],a)&&(r=P2[e+4>>2],P2[r+7052>>2]=0,P2[r+7056>>2]=P2[r+7056>>2]+1,r=P2[(k=f=a=r+6920|0)+4>>2],(a=(e=P2[P2[e>>2]+36>>2])+P2[f>>2]|0)>>>0>>0&&(r=r+1|0),P2[k>>2]=a,P2[f+4>>2]=r,r=1)):(P2[P2[e>>2]>>2]=8,r=0)}return R2=48+n|0,e=r}function le(e,r,a,i,t,n,N,G){var V,Y,R,f,T,U,x,z,o=0,s=0,c=0,u=0,b=0,A=0,j=0,H=0,K=0;R2=Y=R2-176|0,s=13,o=P2[e>>2];e:if(1==P2[o>>2]&&(s=3,!(!a|(t?0:i)||(s=4,7<(u=P2[o+24>>2])+-1>>>0)))){r:{if(2!=(0|u))P2[o+16>>2]=0;else if(P2[o+16>>2])break r;P2[o+20>>2]=0}if(32<=(u=P2[o+28>>2])>>>0)P2[o+16>>2]=0,s=5;else if(s=5,!(20>>0))if(655350<=P2[o+32>>2]+-1>>>0)s=6;else{if(o=P2[e>>2],c=P2[o+36>>2]){if(s=7,65519>>0)break e}else c=P2[o+556>>2]?4096:1152,P2[o+36>>2]=c;if(s=8,!(32<(u=P2[o+556>>2])>>>0||(s=10,c>>>0>>0))){if(u=P2[o+560>>2]){if(s=9,10>>0)break e}else u=P2[(A=o)+28>>2],P2[A+560>>2]=u=u>>>0<=15?5>>0?2+(u>>>1|0)|0:5:16==(0|u)?c>>>0<193?7:c>>>0<385?8:c>>>0<577?9:c>>>0<1153?10:c>>>0<2305?11:c>>>0<4609?12:13:c>>>0<385?13:c>>>0<1153?14:15;if(P2[o+8>>2]){if(s=11,!((c>>>0<4609|48e3>2])&c>>>0<16385))break e;if(!((z=P2[P2[e>>2]+32>>2])+-1>>>0<=655349&&!((z>>>0)%1e3)|z>>>0<65536|!((z>>>0)%10)))break e;if(o=P2[e>>2],4>2]+-8|0,30)>>>0)break e;if(8<(c=P2[o+580>>2])>>>0)break e;if(!(48e3>2])&&4608>2]|12>2])break e}else c=P2[o+580>>2];(u=1<>>0<=c>>>0&&(P2[o+580>>2]=c=u+-1|0),S2[o+576>>2]>=c>>>0&&(P2[o+576>>2]=c);r:if(G&&(c=P2[o+600>>2])&&!((A=P2[o+604>>2])>>>0<2))for(s=1;;){if(!(!(u=P2[(s<<2)+c>>2])|4!=P2[u>>2])){for(;;)if(P2[(o=(s<<2)+c|0)>>2]=P2[((s=s+-1|0)<<2)+c>>2],c=P2[P2[e>>2]+600>>2],!s)break;P2[c>>2]=u,o=P2[e>>2];break r}if((0|A)==(0|(s=s+1|0)))break}A=P2[o+604>>2];r:{a:{if(!(c=P2[o+600>>2])){if(s=12,A)break e;u=0;break r}if(u=0,!A)break r;for(;;){if(!(!(o=P2[(u<<2)+c>>2])|3!=P2[o>>2])){P2[P2[e+4>>2]+7048>>2]=o+16;break a}if((0|A)==(0|(u=u+1|0)))break}}for(u=A=o=0;;){s=12;a:{i:{t:{n:{f:switch(c=P2[(j<<2)+c>>2],P2[c>>2]){case 0:break e;case 6:break i;case 5:break t;case 4:break n;case 3:break f;default:break a}if(H)break e;if(H=1,u=A,b=o,(e=>{var r,a,i,t,n=0,f=0,o=0;if(t=P2[e>>2])for(a=P2[e+4>>2],e=0,o=1;;){if(i=f,r=n,n=G2(e,24)+a|0,!(-1==(0|(f=P2[n>>2]))&-1==(0|(n=P2[n+4>>2]))|o|(0|n)==(0|r)&i>>>0>>0|r>>>0>>0))return;if(!((e=e+1|(o=0))>>>0>>0))break}return 1})(c+16|0))break a;break e}if(u=1,b=o,A)break e;break a}if(u=A,b=o,((e,r)=>{var a=0,i=0,t=0,n=0,f=0,o=0;t:{n:{f:{o:{s:{c:{u:{if(r){if(!(i=r=P2[e+140>>2])&(a=P2[e+136>>2])>>>0<=88199|r>>>0<0){e=0;break t}if(ve(a,i)|T2){e=0;break t}if(!(i=P2[e+148>>2]))break n;if(170==O2[(P2[e+152>>2]+(i<<5)|0)-24|0])break u;e=0;break t}if(!(a=P2[e+148>>2]))break n;for(t=a+-1|0,f=P2[e+152>>2],r=0;;){if(!O2[(e=f+(r<<5)|0)+8|0])break f;i=O2[e+23|0];b:{if(r>>>0>>0){if(!i)break o;if(1>2]+8|0])break s}else if(!i)break b;for(o=e+24|0,e=0;;){if(e&&(n=P2[o>>2]+(e<<4)|0,(O2[n+-8|0]+1|0)!=O2[n+8|0]))break c;if(!((e=e+1|0)>>>0>>0))break}}if((0|a)==(0|(r=r+(e=1)|0)))break}break t}for(f=i+-1|0,o=P2[e+152>>2],r=0;;){if(!(a=O2[(e=o+(r<<5)|0)+8|0]))break f;if(!(170==(0|a)|a>>>0<100)){e=0;break t}if(ve(P2[e>>2],P2[e+4>>2])|T2){e=0;break t}a=O2[e+23|0];u:{b:{if(r>>>0>>0){if(!a)break o;if(O2[P2[e+24>>2]+8|0]<2)break b;break s}if(!a)break u}for(n=P2[e+24>>2],e=0;;){if(ve(P2[(t=n+(e<<4)|0)>>2],P2[t+4>>2])|T2){e=0;break t}if(O2[t+8|0]!=(O2[t+-8|0]+1|0)&&e)break c;if(!((e=e+1|0)>>>0>>0))break}}if((0|i)==(0|(r=r+(e=1)|0)))break}break t}e=0;break t}e=0;break t}e=0;break t}e=0;break t}e=0}return e})(c+16|0,P2[c+160>>2]))break a;break e}if(!W2(V=c+16|0))break e;u=A,b=o;i:switch(P2[V>>2]+-1|0){case 0:if(K)break e;if(ae(b=P2[c+20>>2],10763)&&ae(b,10773))break e;if(32!=P2[c+28>>2])break e;if(K=1,u=A,b=o,32==P2[c+32>>2])break a;break e;case 1:break i;default:break a}if(b=1,o)break e}if(o=P2[e>>2],(j=j+1|0)>>>0>=S2[o+604>>2])break r;c=P2[o+600>>2],o=b,A=u}}if(c=0,j=P2[e+4>>2],P2[j>>2]=0,P2[o+24>>2])for(;;)if(P2[4+((o=c<<2)+j|0)>>2]=0,P2[7328+(o+P2[e+4>>2]|0)>>2]=0,P2[44+(o+P2[e+4>>2]|0)>>2]=0,P2[7368+(o+P2[e+4>>2]|0)>>2]=0,j=P2[e+4>>2],!((c=c+1|0)>>>0>2]+24>>2]))break;if(P2[j+36>>2]=o=0,P2[P2[e+4>>2]+7360>>2]=0,P2[P2[e+4>>2]+76>>2]=0,P2[P2[e+4>>2]+7400>>2]=0,P2[P2[e+4>>2]+40>>2]=0,P2[P2[e+4>>2]+7364>>2]=0,P2[P2[e+4>>2]+80>>2]=0,P2[P2[e+4>>2]+7404>>2]=0,s=P2[e+4>>2],c=P2[e>>2],P2[c+40>>2])for(;;)if(P2[84+((b=o<<2)+s|0)>>2]=0,P2[7408+(b+P2[e+4>>2]|0)>>2]=0,s=P2[e+4>>2],c=P2[e>>2],!((o=o+1|0)>>>0>2]))break;if(P2[s+7536>>2]=o=0,P2[s+212>>2]=0,P2[c+24>>2])for(;;)if(P2[256+((b=o<<3)+s|0)>>2]=0,P2[7540+(b+P2[e+4>>2]|0)>>2]=0,P2[260+(b+P2[e+4>>2]|0)>>2]=0,P2[7544+(b+P2[e+4>>2]|0)>>2]=0,s=P2[e+4>>2],!((o=o+1|(P2[6768+(s+(o<<2)|0)>>2]=0))>>>0>2]+24>>2]))break;P2[s+320>>2]=0,P2[P2[e+4>>2]+7604>>2]=0,P2[P2[e+4>>2]+324>>2]=0,P2[P2[e+4>>2]+7608>>2]=0,o=P2[e+4>>2],P2[o+6800>>2]=0,P2[o+328>>2]=0,P2[P2[e+4>>2]+7612>>2]=0,P2[P2[e+4>>2]+332>>2]=0,P2[P2[e+4>>2]+7616>>2]=0,o=P2[e+4>>2],P2[o+7620>>2]=0,P2[o+7624>>2]=0,P2[o+6848>>2]=0,P2[o+6852>>2]=0,P2[o+6804>>2]=0,b=P2[e>>2],A=P2[b+36>>2],b=P2[b+32>>2],P2[o+7052>>2]=0,P2[o+7056>>2]=0,P2[o+6864>>2]=0,P2[(s=o)+6860>>2]=(b=(z=.4*(b>>>0)/(A>>>0)+.5)<4294967296&0<=z?~~z>>>0:0)||1,Z2(o+7156|0),s=P2[e+4>>2],P2[s+7244>>2]=12,P2[s+7240>>2]=13,P2[s+7236>>2]=12,P2[s+7228>>2]=14,P2[s+7224>>2]=15,P2[s+7220>>2]=16,P2[s+7232>>2]=17,c=P2[e>>2],P2[c>>2]=0;r:{a:{i:{if(P2[s+7260>>2]=G){if(!(x=J2((x=c+632|0)+8|0,P2[x>>2])?0:(P2[x+392>>2]=0,P2[x+396>>2]=0,P2[x+384>>2]=0,P2[x+388>>2]=1)))break i;c=P2[e>>2],s=P2[e+4>>2]}if(o=e+4|0,P2[s+7276>>2]=a,P2[s+7264>>2]=r,P2[s+7288>>2]=N,P2[s+7280>>2]=n,P2[s+7272>>2]=t,P2[s+7268>>2]=i,r=P2[c+36>>2],S2[s>>2]>>0){i=r+5|0;t:{n:{f:{if(P2[c+24>>2])for(a=0;;){if(N=q2(i,(t=(n=a<<2)+P2[o>>2]|0)+7328|0,t+4|0),t=P2[4+(n+P2[o>>2]|0)>>2],P2[t>>2]=0,P2[t+4>>2]=0,P2[t+8>>2]=0,P2[t+12>>2]=0,t=4+(n+P2[o>>2]|0)|0,P2[t>>2]=P2[t>>2]+16,!N)break f;if(!((a=a+1|0)>>>0>2]+24>>2]))break}if(a=P2[o>>2],t=q2(i,a+7360|0,a+36|0),a=P2[P2[o>>2]+36>>2],P2[a>>2]=0,P2[a+4>>2]=0,P2[a+8>>2]=0,P2[a+12>>2]=0,a=P2[o>>2],P2[a+36>>2]=P2[a+36>>2]+16,a=t?(i=q2(i,(a=P2[o>>2])+7364|0,a+40|0),a=P2[P2[o>>2]+40>>2],P2[a>>2]=0,P2[a+4>>2]=0,P2[a+8>>2]=0,P2[a+12>>2]=0,a=P2[o>>2]+40|0,P2[a>>2]=P2[a>>2]+16,0!=(0|i)):0!=(0|t)){if(i=P2[e>>2],P2[i+556>>2]){if(a=P2[o>>2],P2[i+40>>2])for(s=0;;){if(!q2(r,(a=(s<<2)+a|0)+7408|0,a+84|0))break f;if(a=P2[e+4>>2],!((s=s+1|0)>>>0>2]+40>>2]))break}if(!q2(r,a+7536|0,a+212|0))break f}for(c=1,n=N=0;;){if(n>>>0>2]+24>>2]){for(a=1,i=s=0;;){if(1&s)break f;if(G=a&0!=(0|(t=q2(r,(i=(P2[o>>2]+(n<<3)|0)+(i<<2)|0)+7540|0,i+256|0))),s=!t,i=1,a=0,!G)break}if(n=n+1|0,t)continue;break f}break}for(G=1;;){if(a=1,i=s=0,!G)break f;for(;;){if(1&s)break f;if(n=a&0!=(0|(t=q2(r,(i=(P2[o>>2]+(N<<3)|0)+(i<<2)|0)+7604|0,i+320|0))),s=!t,i=1,a=0,!n)break}if(a=c&(G=0!=(0|t)),N=1,c=0,!a)break}if(t){if(i=r<<1,a=P2[e+4>>2],f=a+7620|0,T=a+6848|0,536870911<(R=i)>>>(U=0)||(R=x2(R?R<<3:1))&&((U=P2[f>>2])&&z2(U),P2[f>>2]=R,P2[T>>2]=R,U=1),a=U,s=P2[e>>2],!(t=P2[s+572>>2])|!a)break n;if(q2(i,(a=P2[o>>2])+7624|0,a+6852|0))break t}}}s=P2[e>>2];break r}if(t|!a)break r}if(s=P2[o>>2],(0|r)!=P2[s>>2]&&(a=P2[e>>2],!(!P2[a+556>>2]|!P2[a+40>>2]))){for(s=0;;){t:{n:{f:{o:{s:{c:{u:{b:{A:{k:{l:{_:{d:{m:{g:{p:{w:{h:{v:switch(P2[(a=(s<<4)+a|0)+44>>2]){case 16:break f;case 15:break o;case 14:break s;case 13:break c;case 12:break u;case 11:break b;case 10:break A;case 9:break k;case 8:break l;case 7:break _;case 6:break d;case 5:break m;case 4:break g;case 3:break p;case 2:break w;case 1:break h;case 0:break v;default:break n}W=Z=X=m=d=_=l=k=J=void 0;var W,J=P2[84+(P2[o>>2]+(s<<2)|0)>>2],k=r,l=0,_=V2(0),d=0,m=V2(0),X=0,Z=k+-1|0;if(1&k){if(d=(0|Z)/2|0,0<=(0|k))for(X=(W=0<(0|d)?d:0)+1|0,m=V2(0|Z);;)if(_=V2(0|l),N2[(l<<2)+J>>2]=V2(_+_)/m,d=(0|l)==(0|W),l=l+1|0,d)break;if(!((0|k)<=(0|X)))for(m=V2(0|Z);;)if(_=V2(0|X),N2[(X<<2)+J>>2]=V2(2)-V2(V2(_+_)/m),(0|(X=X+1|0))==(0|k))break}else{if(d=(0|k)/2|0,2<=(0|k)){for(m=V2(0|Z);;)if(_=V2(0|l),N2[(l<<2)+J>>2]=V2(_+_)/m,(0|d)==(0|(l=l+1|0)))break;l=d}if(!((0|k)<=(0|l)))for(m=V2(0|Z);;)if(_=V2(0|l),N2[(l<<2)+J>>2]=V2(2)-V2(V2(_+_)/m),(0|(l=l+1|0))==(0|k))break}break t}$=q=e0=i0=a0=r0=void 0;var q,$,e0,r0=P2[84+(P2[o>>2]+(s<<2)|0)>>2],a0=r,i0=0;if(V2(0),V2(0),V2(0),1<=(0|a0))for(q=V2(a0+-1|0);;)if(e0=V2(V2(0|i0)/q),$=(i0<<2)+r0|0,e0=V2(-.47999998927116394*+V2(Y2(V2(e0+V2(-.5))))+.6200000047683716+-.3799999952316284*H2(6.283185307179586*+e0)),N2[$>>2]=e0,(0|(i0=i0+1|0))==(0|a0))break;break t}n0=f0=t0=c0=s0=o0=void 0;var t0,n0,f0,o0=P2[84+(P2[o>>2]+(s<<2)|0)>>2],s0=r,c0=0;if(V2(0),1<=(0|s0))for(t0=s0+-1|0;;)if(n0=(c0<<2)+o0|0,f0=V2(.07999999821186066*H2(12.566370614359172*(f0=0|c0)/t0)+(-.5*H2(6.283185307179586*f0/t0)+.41999998688697815)),N2[n0>>2]=f0,(0|(c0=c0+1|0))==(0|s0))break;break t}b0=A0=u0=_0=l0=k0=void 0;var u0,b0,A0,k0=P2[84+(P2[o>>2]+(s<<2)|0)>>2],l0=r,_0=0;if(V2(0),1<=(0|l0))for(u0=l0+-1|0;;)if(b0=(_0<<2)+k0|0,A0=V2(.14127999544143677*H2(12.566370614359172*(A0=0|_0)/u0)+(-.488290011882782*H2(6.283185307179586*A0/u0)+.35874998569488525)+-.011680000461637974*H2(18.84955592153876*A0/u0)),N2[b0>>2]=A0,(0|(_0=_0+1|0))==(0|l0))break;break t}m0=w0=d0=p0=g0=void 0;var d0,m0,g0=P2[84+(P2[o>>2]+(s<<2)|0)>>2],p0=r,w0=0;if(1<=(0|p0))for(m0=.5*(p0+-1|0);;)if(N2[(w0<<2)+g0>>2]=(d0=1-(d0=((0|w0)-m0)/m0)*d0)*d0,(0|(w0=w0+1|0))==(0|p0))break;break t}E0=C0=y0=v0=F0=L0=h0=D0=B0=void 0;var h0,v0,y0,C0,E0,F0,B0=P2[84+(P2[o>>2]+(s<<2)|0)>>2],D0=r,L0=0;if(V2(0),1<=(0|D0))for(h0=D0+-1|0;;)if(v0=H2(12.566370614359172*(F0=0|L0)/h0),y0=H2(6.283185307179586*F0/h0),C0=H2(18.84955592153876*F0/h0),E0=(L0<<2)+B0|0,F0=V2(.0069473679177463055*H2(25.132741228718345*F0/h0)+(.27726316452026367*v0+(-.4166315793991089*y0+.21557894349098206)+-.08357894420623779*C0)),N2[E0>>2]=F0,(0|(L0=L0+1|0))==(0|D0))break;break t}ie(P2[84+(P2[o>>2]+(s<<2)|0)>>2],r,N2[a+48>>2]);break t}Q0=M0=I0=S0=O0=P0=void 0;var I0,M0,Q0,P0=P2[84+(P2[o>>2]+(s<<2)|0)>>2],O0=r,S0=0;if(V2(0),1<=(0|O0))for(I0=O0+-1|0;;)if(M0=(S0<<2)+P0|0,Q0=V2(-.46000000834465027*H2(6.283185307179586*(0|S0)/I0)+.5400000214576721),N2[M0>>2]=Q0,(0|(S0=S0+1|0))==(0|O0))break;break t}te(P2[84+(P2[o>>2]+(s<<2)|0)>>2],r);break t}G0=V0=N0=T0=R0=Y0=void 0;var N0,G0,V0,Y0=P2[84+(P2[o>>2]+(s<<2)|0)>>2],R0=r,T0=0;if(V2(0),1<=(0|R0))for(N0=R0+-1|0;;)if(G0=(T0<<2)+Y0|0,V0=V2(.09799999743700027*H2(12.566370614359172*(V0=0|T0)/N0)+(-.49799999594688416*H2(6.283185307179586*V0/N0)+.4020000100135803)+-.0010000000474974513*H2(18.84955592153876*V0/N0)),N2[G0>>2]=V0,(0|(T0=T0+1|0))==(0|R0))break;break t}x0=z0=U0=K0=H0=j0=void 0;var U0,x0,z0,j0=P2[84+(P2[o>>2]+(s<<2)|0)>>2],H0=r,K0=0;if(V2(0),1<=(0|H0))for(U0=H0+-1|0;;)if(x0=(K0<<2)+j0|0,z0=V2(.13659949600696564*H2(12.566370614359172*(z0=0|K0)/U0)+(-.48917749524116516*H2(6.283185307179586*z0/U0)+.36358189582824707)+-.010641099885106087*H2(18.84955592153876*z0/U0)),N2[x0>>2]=z0,(0|(K0=K0+1|0))==(0|H0))break;break t}X0=J0=W0=void 0;var W0=P2[84+(P2[o>>2]+(s<<2)|0)>>2],J0=r,X0=0;if(1<=(0|J0))for(;;)if(P2[(X0<<2)+W0>>2]=1065353216,(0|(X0=X0+1|0))==(0|J0))break;break t}e2=$0=q0=h=w=p=g=Z0=void 0;var Z0=P2[84+(P2[o>>2]+(s<<2)|0)>>2],g=r,p=0,w=0,h=V2(0),q0=0,$0=V2(0),e2=0,w=1;if(1&g){if(p=(g+1|0)/2|0,1<=(0|g))for(h=V2(V2(0|g)+V2(1)),w=(q0=1<(0|p)?p:1)+1|0,p=1;;)if($0=V2(0|p),N2[((p<<2)+Z0|0)-4>>2]=V2($0+$0)/h,e2=(0|p)==(0|q0),p=p+1|0,e2)break;if(!((0|g)<(0|w)))for(h=V2(V2(0|g)+V2(1));;)if(N2[((w<<2)+Z0|0)-4>>2]=V2(2+(g-w<<1)|0)/h,p=(0|g)==(0|w),w=w+1|0,p)break}else{if(p=1,2<=(0|g))for(p=(q0=g>>>1|0)+1|0,h=V2(V2(0|g)+V2(1));;)if($0=V2(0|w),N2[((w<<2)+Z0|0)-4>>2]=V2($0+$0)/h,e2=(0|w)==(0|q0),w=w+1|0,e2)break;if(!((0|g)<(0|p)))for(h=V2(V2(0|g)+V2(1));;)if(N2[((p<<2)+Z0|0)-4>>2]=V2(2+(g-p<<1)|0)/h,w=(0|g)!=(0|p),p=p+1|0,!w)break}break t}o2=f2=r2=n2=t2=y=i2=v=a2=void 0;var r2,a2=P2[84+(P2[o>>2]+(s<<2)|0)>>2],v=r,i2=N2[a+48>>2],y=0,t2=0,n2=0,f2=0,o2=V2(0);if(i2<=V2(0)){if(!((0|v)<1))for(;;)if(P2[(y<<2)+a2>>2]=1065353216,(0|(y=y+1|0))==(0|v))break}else if(i2>=V2(1)){if(!((0|v)<1))for(n2=v+-1|0;;)if(f2=(y<<2)+a2|0,o2=V2(.5-.5*H2(6.283185307179586*(0|y)/n2)),N2[f2>>2]=o2,(0|(y=y+1|0))==(0|v))break}else{if(i2=V2(V2(i2*V2(.5))*V2(0|v)),t2=V2(Y2(i2))>2]=1065353216,(0|(y=y+1|0))==(0|v))break;if(!((0|t2)<2))for(v=v-t2|0,n2=0|(r2=t2+-1|0),y=0;;)if(f2=(y<<2)+a2|0,o2=V2(.5-.5*H2(3.141592653589793*(0|y)/n2)),N2[f2>>2]=o2,f2=(v+y<<2)+a2|0,o2=V2(.5-.5*H2(3.141592653589793*(y+r2|0)/n2)),N2[f2>>2]=o2,(0|t2)==(0|(y=y+1|0)))break}break t}m2=d2=c2=_2=l2=k2=A2=s2=b2=L=D=B=F=E=C=u2=void 0;for(var s2,c2,u2=P2[84+(P2[o>>2]+(s<<2)|0)>>2],C=r,E=N2[a+48>>2],F=N2[a+52>>2],B=N2[a+56>>2],D=0,L=0,b2=0,A2=0,k2=0,l2=V2(0),_2=0,d2=0,m2=V2(0);l2=E,E=V2(.05000000074505806),l2<=V2(0)||(E=V2(.949999988079071),l2>=V2(1)););if(E=V2(0|C),F=V2(E*F),L=V2(Y2(F))>>0<(s2=C+-1|0)>>>0?D:s2)<<2)|0),D=s2+1|0;;)if(c2=(0|A2)==(0|s2),A2=A2+1|0,c2)break;L=L+b2|0;s:if(!((0|L)<=(0|D)|(0|C)<=(0|D)))for(_2=0|b2,A2=1;;){if(d2=(D<<2)+u2|0,m2=V2(.5-.5*H2(3.141592653589793*(0|A2)/_2)),N2[d2>>2]=m2,(0|L)<=(0|(D=D+1|0)))break s;if(A2=A2+1|0,!((0|D)<(0|C)))break}L=k2-b2|0;s:if(!((0|L)<=(0|D)|(0|C)<=(0|D)))for(;;){if(P2[(D<<2)+u2>>2]=1065353216,(0|L)<=(0|(D=D+1|0)))break s;if(!((0|D)<(0|C)))break}s:if(!((0|k2)<=(0|D)|(0|C)<=(0|D)))for(_2=0|b2;;){if(d2=(D<<2)+u2|0,m2=V2(.5-.5*H2(3.141592653589793*(0|b2)/_2)),N2[d2>>2]=m2,(0|k2)<=(0|(D=D+1|0)))break s;if(b2=b2+-1|0,!((0|D)<(0|C)))break}(0|D)<(0|C)&&U2((D<<2)+u2|0,C-D<<2);break t}F2=E2=g2=C2=y2=v2=h2=S=O=P=Q=M=F=B=w2=I=p2=void 0;for(var g2,p2=P2[84+(P2[o>>2]+(s<<2)|0)>>2],I=r,w2=N2[a+48>>2],B=N2[a+52>>2],F=N2[a+56>>2],M=0,Q=0,P=0,O=0,S=0,h2=0,v2=0,y2=V2(0),C2=0,E2=(V2(0),0),F2=V2(0);y2=w2,w2=V2(.05000000074505806),y2<=V2(0)||(w2=V2(.949999988079071),y2>=V2(1)););if(g2=w2=V2(y2*V2(.5)),y2=V2(0|I),B=V2(y2*B),h2=V2(Y2(B))>>0>>0?Q:I,v2=0|Q,O=0,C2=1;;)if(E2=(O<<2)+p2|0,F2=V2(.5-.5*H2(3.141592653589793*(0|C2)/v2)),N2[E2>>2]=F2,C2=C2+1|0,(0|(O=O+1|0))==(0|M))break;O=h2-Q|0;o:if(!((0|O)<=(0|M)|(0|I)<=(0|M)))for(;;){if(P2[(M<<2)+p2>>2]=1065353216,(0|O)<=(0|(M=M+1|0)))break o;if(!((0|M)<(0|I)))break}o:if(!((0|h2)<=(0|M)|(0|I)<=(0|M)))for(v2=0|Q;;){if(E2=(M<<2)+p2|0,F2=V2(.5-.5*H2(3.141592653589793*(0|Q)/v2)),N2[E2>>2]=F2,(0|h2)<=(0|(M=M+1|0)))break o;if(Q=Q+-1|0,!((0|M)<(0|I)))break}o:if(!((0|S)<=(0|M)|(0|I)<=(0|M)))for(U2((M<<2)+p2|0,4+(((h2=(Q=-1^M)+S|0)>>>0<(Q=I+Q|0)>>>0?h2:Q)<<2)|0);;){if((0|S)<=(0|(M=M+1|0)))break o;if(!((0|M)<(0|I)))break}S=P+S|0;o:if(!((0|S)<=(0|M)|(0|I)<=(0|M)))for(v2=0|P,Q=1;;){if(E2=(M<<2)+p2|0,F2=V2(.5-.5*H2(3.141592653589793*(0|Q)/v2)),N2[E2>>2]=F2,(0|S)<=(0|(M=M+1|0)))break o;if(Q=Q+1|0,!((0|M)<(0|I)))break}Q=I-P|0;o:if(!((0|Q)<=(0|M)|(0|I)<=(0|M)))for(;;){if(P2[(M<<2)+p2>>2]=1065353216,(0|Q)<=(0|(M=M+1|0)))break o;if(!((0|M)<(0|I)))break}if((0|M)<(0|I))for(v2=0|P;;)if(E2=(M<<2)+p2|0,F2=V2(.5-.5*H2(3.141592653589793*(0|P)/v2)),N2[E2>>2]=F2,P=P+-1|0,(0|(M=M+1|0))==(0|I))break;break t}D2=B2=M2=I2=L2=void 0;var B2,D2,L2=P2[84+(P2[o>>2]+(s<<2)|0)>>2],I2=r,M2=0;if(1<=(0|I2))for(B2=.5*(I2+-1|0);;)if(N2[(M2<<2)+L2>>2]=1-(D2=((0|M2)-B2)/B2)*D2,(0|(M2=M2+1|0))==(0|I2))break;break t}te(P2[84+(P2[o>>2]+(s<<2)|0)>>2],r)}if(a=P2[e>>2],!((s=s+1|0)>>>0>2]))break}s=P2[o>>2]}P2[s>>2]=r}if(f=P2[s+6856>>2],P2[f+16>>2]=0,P2[f+8>>2]=8192,P2[f+12>>2]=0,T=f,f=x2(32768),r=0!=(0|(P2[T>>2]=f)),i=P2[e>>2],!r){P2[i>>2]=8,s=1;break e}if(P2[i+4>>2]){a=P2[o>>2],r=P2[i+36>>2]+(s=1)|0,P2[a+11796>>2]=r;t:if(P2[i+24>>2]){if(r=$2(4,r),P2[P2[e+4>>2]+11764>>2]=r,i=P2[e>>2],r)for(;;){if(a=P2[o>>2],s>>>0>=S2[i+24>>2])break t;if(r=$2(4,P2[a+11796>>2]),P2[11764+(P2[e+4>>2]+(s<<2)|0)>>2]=r,s=s+1|0,i=P2[e>>2],!r)break}P2[i>>2]=8,s=1;break e}if(P2[a+11800>>2]=0,!((a=P2[a+11752>>2])||(a=ee(),P2[P2[o>>2]+11752>>2]=a))){P2[P2[e>>2]>>2]=3,s=1;break e}if(r=re(a,18,0,0,0,0,19,20,21,e),i=P2[e>>2],r)break a;a=!P2[i+4>>2]}else a=1;if(r=P2[o>>2],P2[r+7312>>2]=0,P2[r+7316>>2]=0,P2[r+7292>>2]=0,P2[(t=r+11816|0)>>2]=0,P2[t+4>>2]=0,P2[(t=r+11824|0)>>2]=0,P2[t+4>>2]=0,P2[(t=r+11832|0)>>2]=0,P2[t+4>>2]=0,P2[r+11840>>2]=0,P2[i+624>>2]=0,P2[i+628>>2]=0,P2[i+616>>2]=0,P2[i+620>>2]=0,P2[i+608>>2]=0,P2[i+612>>2]=0,a||(P2[r+11756>>2]=0),!j2(P2[r+6856>>2],P2[1354],P2[1355])){P2[P2[e>>2]>>2]=7,s=1;break e}if(s=1,!_e(e,0,0))break e;if(r=P2[e+4>>2],a=P2[e>>2],P2[a+4>>2]&&(P2[r+11756>>2]=1),P2[r+6872>>2]=0,P2[r+6876>>2]=0,P2[r+6880>>2]=34,P2[r+6888>>2]=P2[a+36>>2],P2[P2[e+4>>2]+6892>>2]=P2[P2[e>>2]+36>>2],P2[P2[e+4>>2]+6896>>2]=0,P2[P2[e+4>>2]+6900>>2]=0,P2[P2[e+4>>2]+6904>>2]=P2[P2[e>>2]+32>>2],P2[P2[e+4>>2]+6908>>2]=P2[P2[e>>2]+24>>2],P2[P2[e+4>>2]+6912>>2]=P2[P2[e>>2]+28>>2],r=P2[e>>2],a=P2[r+596>>2],i=P2[e+4>>2]+6920|0,P2[i>>2]=P2[r+592>>2],P2[i+4>>2]=a,r=P2[e+4>>2],P2[(a=r+6936|0)>>2]=0,P2[a+4>>2]=0,P2[(r=r+6928|0)>>2]=0,P2[r+4>>2]=0,P2[P2[e>>2]+12>>2]&&X2(P2[o>>2]+7060|0),!ne((r=P2[o>>2])+6872|0,P2[r+6856>>2])){P2[P2[e>>2]>>2]=7;break e}if(!_e(e,0,0))break e;if(P2[P2[o>>2]+6896>>2]=-1<>2]+6920|0,P2[r>>2]=0,P2[r+4>>2]=0,!u){if(P2[Y>>2]=4,a=P2[P2[e>>2]+604>>2],P2[(r=Y)+24>>2]=0,P2[r+28>>2]=0,P2[r+16>>2]=0,P2[r+20>>2]=0,P2[r+8>>2]=8,P2[r+4>>2]=!a,!ne(r,P2[P2[e+4>>2]+6856>>2])){P2[P2[e>>2]>>2]=7;break e}if(!_e(e,0,0))break e}t:if(i=P2[e>>2],t=P2[i+604>>2]){for(a=0;;){if(r=P2[P2[i+600>>2]+(a<<2)>>2],P2[r+4>>2]=(t+-1|0)==(0|a),!ne(r,P2[P2[o>>2]+6856>>2])){P2[P2[e>>2]>>2]=7;break e}if(!_e(e,0,0))break;if(i=P2[e>>2],(t=P2[i+604>>2])>>>0<=(a=a+1|0)>>>0)break t}break e}if(r=P2[o>>2],(a=P2[r+7272>>2])&&(r=0|Q2[a](e,i+624|0,P2[r+7288>>2]),i=P2[e>>2],1==(0|r))){P2[i>>2]=5;break e}if(s=0,!P2[i+4>>2])break e;P2[P2[o>>2]+11756>>2]=2;break e}P2[P2[e>>2]>>2]=2,s=1;break e}P2[i>>2]=3,s=1;break e}P2[s>>2]=8,s=1}}}return R2=176+Y|0,s}function _e(e,r,a){var i,t,n,f,o,s,c,u,b,A,k=0,l=0,_=0,d=0,m=0,g=0,p=0;R2=A=R2-16|0,l=$0(P2[P2[e+4>>2]+6856>>2],4+A|0,A),k=P2[e>>2];e:{if(l){if(P2[k+4>>2])if(k=P2[e+4>>2],P2[k+11804>>2]=P2[4+A>>2],P2[k+11812>>2]=P2[A>>2],P2[k+11756>>2]){if(!j0(P2[k+11752>>2])){if(Z0(P2[P2[e+4>>2]+6856>>2]),e=P2[e>>2],4==P2[e>>2])break e;P2[e>>2]=3;break e}}else P2[k+11760>>2]=1;if(t=P2[A>>2],f=P2[4+A>>2],P2[8+A>>2]=0,P2[12+A>>2]=0,k=P2[e+4>>2],!(l=P2[k+7272>>2])||1!=(0|Q2[l](e,8+A|0,P2[k+7288>>2]))){r:if(!r){a:switch(127&O2[0|f]){case 0:k=P2[12+A>>2],l=P2[e>>2],P2[l+608>>2]=P2[8+A>>2],P2[l+612>>2]=k;break r;case 3:break a;default:break r}k=P2[e>>2],P2[k+616>>2]|P2[k+620>>2]||(l=P2[12+A>>2],P2[k+616>>2]=P2[8+A>>2],P2[k+620>>2]=l)}_=P2[e+4>>2],d=P2[_+7048>>2];r:if(d&&(m=P2[e>>2],(k=P2[(l=m)+628>>2])|(o=P2[l+624>>2]))&&(s=P2[d>>2])&&!(s>>>0<=(g=P2[_+7292>>2])>>>0))for(l=n=P2[_+7316>>2],p=(l=(l=(i=(c=P2[_+7312>>2])+(m=u=P2[m+36>>2])|0)>>>0>>0?l+1|0:l)+-1|0)+1|0,m=l,m=-1!=(0|(l=i-1|0))?p:m,b=P2[d+4>>2];;){if(d=b+G2(g,24)|0,p=P2[d>>2],(0|m)==(0|(i=P2[d+4>>2]))&l>>>0

>>0|m>>>0>>0)break r;if((0|i)==(0|n)&c>>>0<=p>>>0|n>>>0>>0&&(P2[d>>2]=c,P2[d+4>>2]=n,i=P2[8+A>>2],p=P2[12+A>>2],P2[d+16>>2]=u,P2[d+8>>2]=i-o,P2[d+12>>2]=p-(k+(i>>>0>>0)|0)),(0|(P2[_+7292>>2]=g=g+1|0))==(0|s))break}if(!(a=P2[_+7260>>2]?s2(P2[e>>2]+632|0,f,t,r,P2[_+7056>>2],a,P2[_+7276>>2],e,P2[_+7288>>2]):0|Q2[P2[_+7276>>2]](e,f,t,r,P2[_+7056>>2],P2[_+7288>>2]))){if(a=P2[e+4>>2],l=P2[(m=k=a)+7308>>2],(_=t+P2[k+7304>>2]|0)>>>0>>0&&(l=l+1|0),P2[m+7304>>2]=_,P2[k+7308>>2]=l,k=P2[a+7316>>2],(l=P2[a+7312>>2]+r|0)>>>0>>0&&(k=k+1|0),P2[a+7312>>2]=l,P2[a+7316>>2]=k,k=P2[(l=a)+7320>>2],a=P2[a+7056>>2]+(g=1)|0,P2[l+7320>>2]=a>>>0>>0?k:a,Z0(P2[P2[e+4>>2]+6856>>2]),!r)break e;r=P2[e+4>>2]+6896|0,a=P2[r>>2],l=r,r=P2[A>>2],P2[l>>2]=r>>>0>>0?r:a,a=P2[e+4>>2]+6900|0,e=P2[a>>2],P2[a>>2]=e>>>0>>0?r:e;break e}}P2[P2[e>>2]>>2]=5,Z0(P2[P2[e+4>>2]+6856>>2]),P2[P2[e>>2]>>2]=5}else P2[k>>2]=8;g=0}return R2=16+A|0,g}function de(e,r,N,a,i,t,n,G,V,Y,R){var f,o,s,T,c,U,x,z,j,H,K,W,J,X,u,b,Z,A=0,k=0,l=0,_=0,d=0,m=0,g=0,p=0,w=0,h=0,v=0,y=0,C=0,E=0,F=0,B=0,q=0,$=0,e0=0,r0=0,a0=(V2(0),0),i0=0,t0=0;V2(0);R2=u=R2-576|0,o=P2[(16>2]+28>>2]?5644:5640)>>2],k=P2[a>>2];e:if(P2[P2[e+4>>2]+7256>>2]&&(A=-1,3>>0)||(d=P2[n>>2],P2[d+4>>2]=t,P2[d>>2]=1,A=P2[d+288>>2]+(P2[1416]+(P2[1415]+(P2[1414]+G2(i,k)|0)|0)|0)|0,!((k=P2[a>>2])>>>0<4))){l=P2[e+4>>2],l=4+((31^g0(1|(d=k+-4|0)))+i|0)>>>0<=32?0|Q2[P2[l+7224>>2]](t+16|0,d,416+u|0):0|Q2[P2[l+7228>>2]](t+16|0,d,416+u|0);r:{a:{i:{t:if(_=P2[e+4>>2],!(P2[_+7248>>2]|N2[420+u>>2]!=V2(0))){if(m=P2[t>>2],(d=P2[a>>2])>>>0<=(k=1))break i;for(;;){if((0|m)!=P2[(k<<2)+t>>2])break t;if(!((k=k+1|0)>>>0>>0))break}break i}if(k=P2[e>>2],!P2[_+7252>>2]){d=A;break a}if((d=-1)!=(0|A)){d=A;break r}if(!P2[k+556>>2])break a;d=A;break r}e=P2[n+4>>2],P2[e+4>>2]=m,P2[e>>2]=0,A=(p=(e=P2[e+288>>2]+(P2[1416]+(P2[1415]+(P2[1414]+i|0)|0)|0)|0)>>>0>>0)?e:A;break e}if(g=(A=P2[k+568>>2])?0:l,!((F=(l=A?4:l)>>>0<(A=P2[a>>2])>>>0?l:A+-1|0)>>>0>>0)){for($=o+-1|0,e0=P2[1416],B=P2[1415],r0=P2[1414],z=V2(i>>>0);;){if(!(z<=(T=N2[(k=g<<2)+(416+u|0)>>2]))){if(a0=P2[(m=(q=!p)<<2)+G>>2],w=P2[n+m>>2],v=P2[P2[e>>2]+572>>2],A=P2[e+4>>2],l=P2[A+6852>>2],_=P2[A+6848>>2],((e,r,a,i)=>{var t=0,n=0;a:{i:{t:switch(0|a){case 4:if(((a=0)|r)<=0)break i;for(;;)if(P2[i+(n=a<<2)>>2]=(P2[(t=n+e|0)+-16>>2]+(P2[t>>2]+G2(P2[t+-8>>2],6)|0)|0)-(P2[t+-12>>2]+P2[t+-4>>2]<<2),(0|(a=a+1|0))==(0|r))break;break i;case 3:if(((a=0)|r)<=0)break i;for(;;)if(P2[i+(n=a<<2)>>2]=(P2[(t=n+e|0)>>2]-P2[t+-12>>2]|0)+G2(P2[t+-8>>2]-P2[t+-4>>2]|0,3),(0|(a=a+1|0))==(0|r))break;break i;case 2:if(((a=0)|r)<=0)break i;for(;;)if(P2[i+(n=a<<2)>>2]=P2[(t=n+e|0)+-8>>2]+(P2[t>>2]-(P2[t+-4>>2]<<1)|0),(0|(a=a+1|0))==(0|r))break;break i;case 0:break a;case 1:break t;default:break i}if(!(((a=0)|r)<=0))for(;;)if(P2[i+(n=a<<2)>>2]=P2[(t=n+e|0)>>2]-P2[t+-4>>2],(0|(a=a+1|0))==(0|r))break}return}p0(i,e,r<<2)})(A=t+k|0,k=P2[a>>2]-g|0,g,m=P2[V+m>>2]),P2[w+36>>2]=m,P2[w+12>>2]=a0,P2[w>>2]=2,P2[w+4>>2]=0,i0=T>V2(0),A=(E=+T+.5)<4294967296&0<=E?~~E>>>0:0,_=ge(C=P2[e+4>>2],m,_,l,k,h=g,(A=i0?A+1|0:1)>>>0>>0?A:$,o,r,N,i,v,w+4|0),P2[w+16>>2]=g)for(l=w+20|0,A=0;;)if(P2[(k=A<<2)+l>>2]=P2[t+k>>2],(0|g)==(0|(A=A+1|0)))break;p=(k=(A=P2[w+288>>2]+(e0+(B+(r0+(_+G2(i,g)|0)|0)|0)|0)|0)>>>0>>0)?q:p,d=k?A:d}if(!((g=g+1|0)>>>0<=F>>>0))break}k=P2[e>>2]}}if((l=P2[k+556>>2])&&(A=P2[a>>2],P2[12+u>>2]=l=l>>>0>>0?l:A+-1|0)&&P2[k+40>>2])for(U=33-i|0,j=o+-1|0,H=P2[1413],K=P2[1412],W=P2[1416],w=P2[1415],J=P2[1414],F=(E=i>>>0)<18,$=16>>0,e0=17>>0;;){k=P2[e+4>>2],n0=u0=c0=s0=o0=f0=void 0;var n0,f0=t,o0=P2[84+(k+(t0<<2)|0)>>2],s0=P2[k+212>>2],c0=A,u0=0;if(c0)for(;;)if(N2[(n0=u0<<2)+s0>>2]=N2[o0+n0>>2]*V2(P2[f0+n0>>2]),(0|(u0=u0+1|0))==(0|c0))break;A=P2[e+4>>2],Q2[P2[A+7232>>2]](P2[A+212>>2],P2[a>>2],P2[12+u>>2]+1|0,272+u|0);r:if(N2[272+u>>2]!=V2(0)){b0=D=d0=S=O=P=L=Q=M=I=_0=l0=k0=A0=void 0;var D,b0,L,A0=272+u|0,k0=12+u|0,l0=P2[e+4>>2]+7628|0,_0=16+u|0,I=0,M=0,Q=0,P=0,O=0,S=0,d0=0;R2=L=R2-256|0,b0=P2[k0>>2],S=+N2[A0>>2];a:{for(;;){if((0|M)==(0|b0))break a;if(Q=+V2(-N2[((d0=M+1|0)<<2)+A0>>2]),M){for(D=M>>>1|0,I=0;;)if(Q-=m0[(I<<3)+L>>3]*+N2[(M-I<<2)+A0>>2],(0|M)==(0|(I=I+1|0)))break;if(Q/=S,m0[(M<<3)+L>>3]=Q,I=0,D)for(;;)if(O=m0[(P=(I<<3)+L|0)>>3],m0[P>>3]=O+Q*m0[(P=((-1^I)+M<<3)+L|0)>>3],m0[P>>3]=Q*O+m0[P>>3],(0|D)==(0|(I=I+1|0)))break;1&M&&(O=m0[(P=(D<<3)+L|0)>>3],m0[P>>3]=O+Q*O)}else Q/=S,m0[(M<<3)+L>>3]=Q;for(O=1-Q*Q,I=0;;)if(N2[((M<<7)+l0|0)+(I<<2)>>2]=-V2(m0[(I<<3)+L>>3]),!((I=I+1|0)>>>0<=M>>>0))break;if(S*=O,m0[(M<<3)+_0>>3]=S,M=d0,0==S)break}P2[k0>>2]=d0}if(R2=256+L|0,_=1,k=P2[12+u>>2],m=P2[e>>2],P2[m+568>>2]||(k=((e,r,a,i)=>{var t,n,f=0,o=0,s=0,c=0,u=0,o=1;if(r){for(n=.5/(a>>>0),c=4294967295;;)if(c=(t=(f=(f=0<(f=m0[(s<<3)+e>>3])?0<=(f=.5*N0(n*f)/.6931471805599453)?f:0:f<0?1e32:0)*(a-o>>>0)+(G2(i,o)>>>0))>2],(P2[m+564>>2]?5:P2[m+560>>2])+i|0),_=P2[A+12>>2]=k),(A=P2[a>>2])>>>0<=k>>>0&&(P2[12+u>>2]=k=A+-1|0),!(k>>>0<_>>>0))for(;;){a:if(b=m0[(16+u|0)+((B=_+-1|0)<<3)>>3],Z=A-_|0,!(E<=(y=0>>0)*b)/.6931471805599453)?b:0:b<0?1e32:0)))for(A=0>>0:0,A=(l=A?l+1|0:1)>>>0>>0,k=P2[e>>2],P2[k+564>>2]?(h=5,C=15,e0||14<(m=(-32^g0(_))+U|0)>>>0||(C=5>>0?m:5)):h=C=P2[k+560>>2],r0=A?l:j,c=(_<<2)+t|0,q=31^(A=g0(_)),x=(-32^A)+U|0;;){if(v=P2[a>>2],i0=P2[(A=(l=!p)<<2)+G>>2],f=P2[n+A>>2],s=P2[V+A>>2],a0=P2[k+572>>2],k=P2[e+4>>2],g=P2[k+6852>>2],m=P2[k+6848>>2],X=p,!G0(p=7628+(k+(B<<7)|(A=0))|0,_,k=!F||h>>>0>>0?h:x,448+u|0,444+u|0)){if(v=v-_|0,(p=i+k|0)+q>>>0<=32?(A=P2[e+4>>2],16>>0|$?Q2[P2[A+7236>>2]](c,v,448+u|0,_,P2[444+u>>2],s):Q2[P2[A+7244>>2]](c,v,448+u|0,_,P2[444+u>>2],s)):Q2[P2[P2[e+4>>2]+7240>>2]](c,v,448+u|0,_,P2[444+u>>2],s),P2[f>>2]=3,P2[f+4>>2]=0,P2[f+284>>2]=s,P2[f+12>>2]=i0,g=ge(P2[e+4>>2],s,m,g,v,_,r0,o,r,N,i,a0,f+4|0),P2[f+20>>2]=k,P2[f+16>>2]=_,P2[f+24>>2]=P2[444+u>>2],p0(f+28|0,448+u|0,128),A=0,_)for(;;)if(P2[156+((m=A<<2)+f|0)>>2]=P2[t+m>>2],(0|_)==(0|(A=A+1|0)))break;A=((P2[f+288>>2]+((((g+G2(_,p)|0)+J|0)+w|0)+W|0)|0)+K|0)+H|0}if(p=(k=0!=(0|A)&A>>>0>>0)?l:X,d=k?A:d,C>>>0<(h=h+1|0)>>>0)break a;k=P2[e>>2]}if((_=_+1|0)>>>0>S2[12+u>>2])break r;A=P2[a>>2]}}if(!((t0=t0+1|0)>>>0>2]+40>>2]))break;A=P2[a>>2]}A=d}-1==(0|A)&&(e=P2[a>>2],r=P2[(p<<2)+n>>2],P2[r+4>>2]=t,P2[r>>2]=1,A=P2[r+288>>2]+(P2[1416]+(P2[1415]+(P2[1414]+G2(e,i)|0)|0)|0)|0),P2[Y>>2]=p,P2[R>>2]=A,R2=576+u|0}function me(e,r,a,i,t){var n,f,o,s,c,u=0,u=1;e:{r:{a:switch(P2[i>>2]){case 0:if(n=i+4|0,f=a,o=P2[i+288>>2],c=0,c=!j2(s=t,P2[1417]|0!=(0|o),P2[1416]+(P2[1415]+P2[1414]|0)|0)||o&&!n2(s,o+-1|0)?c:0!=(0|r2(s,P2[n>>2],f)))break e;break r;case 2:if(((e,r,a,i,t)=>{var n=0;i:if(j2(t,P2[1419]|0!=(0|i)|P2[e+12>>2]<<1,P2[1416]+(P2[1415]+P2[1414]|0)|0)&&(!i||n2(t,i+-1|0))){t:if(P2[e+12>>2]){for(i=0;;){if(r2(t,P2[16+((i<<2)+e|0)>>2],a)){if((i=i+1|0)>>>0>2])continue;break t}break}return}if(j2(t,P2[e>>2],P2[1405])){if(!(1>2])){if(!j2(t,P2[e+4>>2],P2[1406]))break i;if(!(1<(a=P2[e>>2])>>>0||(i=r,r=P2[e+8>>2],g2(t,P2[e+32>>2],i,P2[e+12>>2],P2[r>>2],P2[r+4>>2],P2[e+4>>2],1==(0|a)))))break i}n=1}}return n})(i+4|0,r-P2[i+16>>2]|0,a,P2[i+288>>2],t))break e;break r;case 3:if(((e,r,a,i,t)=>{var n=0;i:if(j2(t,(P2[e+12>>2]<<1)-2|P2[1420]|0!=(0|i),P2[1416]+(P2[1415]+P2[1414]|0)|0)&&(!i||n2(t,i+-1|0))){t:if(P2[e+12>>2]){for(i=0;;){if(r2(t,P2[152+((i<<2)+e|0)>>2],a)){if((i=i+1|0)>>>0>2])continue;break t}break}return}if(j2(t,P2[e+16>>2]+-1|0,P2[1412])&&r2(t,P2[e+20>>2],P2[1413])){t:if(P2[e+12>>2]){for(i=0;;){if(r2(t,P2[24+((i<<2)+e|0)>>2],P2[e+16>>2])){if((i=i+1|0)>>>0>2])continue;break t}break}return}if(j2(t,P2[e>>2],P2[1405])){if(!(1>2])){if(!j2(t,P2[e+4>>2],P2[1406]))break i;if(!(1<(a=P2[e>>2])>>>0||(i=r,r=P2[e+8>>2],g2(t,P2[e+280>>2],i,P2[e+12>>2],P2[r>>2],P2[r+4>>2],P2[e+4>>2],1==(0|a)))))break i}n=1}}}return n})(i+4|0,r-P2[i+16>>2]|0,a,P2[i+288>>2],t))break e;break r;case 1:break a;default:break e}if(((e,r,a,i,t)=>{if(e=P2[e>>2],j2(t,P2[1418]|0!=(0|i),P2[1416]+(P2[1415]+P2[1414]|0)|0)&&(!i||n2(t,i+-1|0))){if(!r)return 1;i=0;a:{for(;;){if(!r2(t,P2[e+(i<<2)>>2],a))break a;if((0|(i=i+1|0))==(0|r))break}return 1}}})(i+4|0,r,a,P2[i+288>>2],t))break e}P2[P2[e>>2]>>2]=7,u=0}return u}function ge(e,r,a,i,t,n,f,o,s,c,u,b,A){var k,l,_,d,m,g,N,p,G,V,Y,w,h=0,v=0,y=0,C=0,E=0,F=0,B=0,D=0,L=0,I=0,M=0,Q=0,P=0,O=0,R=0,S=0,v=((e,r,a)=>{for(var i=0;(i=e)&&(e=i+-1|0,r>>>i>>>0<=a>>>0););return i})(c,Y=t+n|0,n);if(Q2[P2[e+7220>>2]](r,a,t,n,w=s>>>0>>0?s:v,v,u),b){if((s=u=0)<=(0|v))for(D=1<(s=1<>>0?s:1,C=Y>>>v|0;;){c=h,Q=(y<<2)+i|(F=E=0);e:{if(B=C-(I=y?0:n)|0){for(;;)if(E=(L=E)|(E=P2[(c<<2)+r>>2])>>31^E,c=c+1|0,(0|B)==(0|(F=F+1|0)))break;if(h=(h+C|0)-I|0,E){c=2+(31^g0(E))|0;break e}}c=1}if(P2[Q>>2]=c,(0|D)==(0|(y=y+1|0)))break}if(!((0|v)<=(0|w)))for(r=v;;){for(r=r+-1|0,c=0;;)if(y=P2[(h=(u<<2)+i|0)>>2],h=P2[h+4>>2],P2[(s<<2)+i>>2]=h>>>0>>0?y:h,s=s+1|0,u=u+2|0,(c=c+1|0)>>>r)break;if(!((0|w)<(0|r)))break}}if((0|v)<(0|w))P2[A+4>>2]=0,a=6;else{for(V=(l=P2[1407])+(G2(f+1|0,t)-(t>>>1|0)|0)|0,m=o+-1|0,g=P2[1409]+P2[1408]|0,I=P2[1406]+P2[1405]|0,Q=f+-1|0;;){e:{D=v,k0(s=(r=G2(N=!P,12)+e|0)+11724|0,6>>0?v:6),p=(O<<2)+i|0,k=(O<<3)+a|0,G=P2[r+11728>>2],_=P2[s>>2];r:if(v){if((d=Y>>>D|0)>>>0<=n>>>0)break e;if(R=F=0,L=I,!b)for(;;){if(E=d-(F?0:n)|0,!(h=P2[(r=k+(F<<3)|0)+4>>2])&268435457<=(C=P2[r>>2])>>>0|0>>0){if(r=E,16777216==((s=u=0)|h)&0>>0|16777216>>0)v=r,c=0;else if(!(((c=0)|h)==(0|(y=(v=r)>>>25|0))&C>>>0<=(B=r<<7)>>>0|h>>>0>>0))for(;;)if(s=s+8|0,y=u<<15|r>>>17,B=r<<15,c=u<<8|r>>>24,r=v=r<<8,u=c,!((0|h)==(0|y)&B>>>0>>0|y>>>0>>0))break;if(!((0|c)==(0|h)&C>>>0<=v>>>0|h>>>0>>0))for(;;)if(s=s+1|0,!((0|h)==(0|(c=y=c<<1|(r=v)>>>31))&(r=v=r<<1)>>>0>>0|c>>>0>>0))break}else{if((u=E)<<3>>>(s=0)<(r=C)>>>0)for(;;)if(s=s+4|0,c=u<<7,u<<=4,!(c>>>0>>0))break;if(!(r>>>0<=u>>>0))for(;;)if(s=s+1|0,!((u<<=1)>>>0>>0))break}if(r=31&(u=(s=s>>>0>>0?s:m)+-1|0),r=((l-(E>>>1|0)|0)+G2(E,s+1|0)|0)+(s?32<=(63&u)>>>0?h>>>r|0:((1<>>r:C<<1)|0,P2[_+(F<<2)>>2]=R=-1==(0|r)?R:s,L=r+L|0,(F=F+1|0)>>>D)break r}for(;;){if(E=d-(F?0:n)|0,!(h=P2[(r=k+(F<<3)|0)+4>>2])&268435457<=(C=P2[r>>2])>>>0|0>>0){if(r=E,!(16777216==((s=u=0)|h)&0>>0|16777216>>0||((c=0)|h)==(0|(y=(v=r)>>>25|0))&C>>>0<=(B=r<<7)>>>0|h>>>0>>0))for(;;)if(s=s+8|0,y=(r=c)<<15|(u=v)>>>17,B=u<<15,c=r<<8,c|=(r=u)>>>24,v=r<<=8,u=c,!((0|h)==(0|y)&B>>>0>>0|y>>>0>>0))break;if(!((0|u)==(0|h)&C>>>0<=r>>>0|h>>>0>>0))for(;;)if(s=s+1|0,!((0|h)==(0|(u=y=u<<1|r>>>31))&(r<<=1)>>>0>>0|u>>>0>>0))break}else{if((u=E)<<3>>>(s=0)<(r=C)>>>0)for(;;)if(s=s+4|0,c=u<<7,u<<=4,!(c>>>0>>0))break;if(!(r>>>0<=u>>>0))for(;;)if(s=s+1|0,!((u<<=1)>>>0>>0))break}if(r=P2[(c=F<<2)+p>>2],u=G2(B=r,E)+g|0,r=31&(y=(s=s>>>0>>0?s:m)+-1|0),v=((l-(E>>>1|0)|0)+G2(E,s+1|0)|0)+(s?32<=(63&y)>>>0?h>>>r|0:((1<>>r:C<<1)|0,P2[c+G>>2]=(r=v>>>0>>0)?0:B,P2[c+_>>2]=r?s:0,L=(r?v:u)+L|0,(F=F+1|0)>>>D)break}}else c=P2[4+k>>2],s=31&(r=Q),u=P2[k>>2],u=-1==(0|(s=(f?32<=(63&r)>>>0?c>>>s|0:((1<>>s:u<<1)+V|0))?0:f,b&&(c=P2[p>>2],v=G2(c,t)+g|0,P2[G>>2]=(r=s>>>0>>0)?0:c,u=r?u:0,s=r?s:v),P2[_>>2]=u,L=s+I|0;if(M=(r=S+-1>>>0>>0)?M:D,P=r?P:N,S=r?S:L,v=D+-1|0,O=(1<>2]=M)>>>0?M:6}k0(r=P2[A+8>>2],a),a=G2(P,12)+e|0,p0(P2[r>>2],P2[a+11724>>2],i=(e=1<>2],P2[a+11728>>2],i),e=1>>0?e:1,a=P2[1410],r=P2[r>>2],s=0;e:{for(;;){if(S2[r+(s<<2)>>2]>>0){if((0|e)!=(0|(s=s+1|0)))continue;break e}break}P2[A>>2]=1}return S}function pe(e,r,a){var i,t=0,n=0,f=0,o=0,s=0,c=0,u=0,b=0;e:{r:{a:{i:{t:{if(!(t=r))return M=(r=e)-G2(e=(e>>>0)/(a>>>0)|0,a)|0,T2=Q=0,e;if(n=a){if(!((o=n+-1|0)&n))break t;s=0-(o=(g0(n)+33|0)-g0(t)|0)|0;break a}if(!e)return Q=t-G2(e=(t>>>(M=0))/0|0,0)|0,T2=0,e;if((t=32-g0(t)|0)>>>0<31)break i;break r}if(M=e&o,1==((Q=0)|n))break e;return a=31&(t=we(n)),e=32<=(63&t)>>>0?r>>>a|(n=0):(n=r>>>a|0,((1<>>a),T2=n,e}o=t+1|0,s=63-t|0}if(t=r,f=31&(n=63&o),f=32<=n>>>0?t>>>f|(n=0):(n=t>>>f|0,((1<>>f),t=31&(s&=63),32<=s>>>0?(r=e<>>32-t|r<>>31)-(i=a&(c=s-((n=n<<1|f>>>31)+(t>>>0>>0)|0)>>31))|0,n=n-(u>>>0>>0)|0,r=r<<1|e>>>31,e=b|e<<1,b=c&=1,!(o=o+-1|0))break;return M=f,Q=n,T2=r<<1|e>>>31,c|e<<1}M=e,Q=r,r=e=0}return T2=r,e}function we(e){return e?31-g0(e+-1^e)|0:32}function b0(e,r,a,i){var t,n,f,o,s,c,u;return r=r,i=i,u=G2(n=(a=a)>>>16|0,f=(t=e)>>>16|0),n=(65535&(f=((c=G2(o=65535&a,s=65535&t))>>>16|0)+G2(f,o)|0))+G2(n,s)|0,t=(G2(r,a)+u|0)+G2(t,i)+(f>>>16)+(n>>>16)|0,T2=t,e=r=65535&c|n<<16}function he(e,r,a){return pe(e,r,a)}function ve(e,r){return pe(e,r,588),T2=Q,M}function K2(e,r){var a;return(-1>>>(a=31&r)&e)<>>e}function ye(){return u.byteLength/65536|0}})(Y0,b,J)},instantiate:function(r,e){return{then:function(e){e({instance:new A.Instance(new A.Module(r))})}}},RuntimeError:Error});function W(e,r,a,i){switch(a="*"===(a=a||"i8").charAt(a.length-1)?"i32":a){case"i1":case"i8":d[e>>0]=r;break;case"i16":t0[e>>1]=r;break;case"i32":m[e>>2]=r;break;case"i64":h=[r>>>0,1<=+m0(w=r)?0>>0:~~+g0((w-(~~w>>>0))/4294967296)>>>0:0],m[e>>2]=h[0],m[e+4>>2]=h[1];break;case"float":n0[e>>2]=r;break;case"double":f0[e>>3]=r;break;default:p("invalid type for setValue: "+a)}}s=[],"object"!=typeof A&&p("no native wasm support detected");var J=new A.Table({initial:22,maximum:27,element:"anyfunc"}),X=!1;function k(e,r){e||p("Assertion failed: "+r)}function Z(e){var r=y["_"+e];return k(r,"Cannot call unknown function "+e+", make sure it is exported"),r}function q(e,r,a,i,t){var n={string:function(e){var r,a=0;return null!=e&&0!==e&&(r=1+(e.length<<2),a0(e,a=z0(r),r)),a},array:function(e){var r=z0(e.length);return d.set(e,r),r}};var e=Z(e),f=[],o=0;if(i)for(var s=0;s>10,56320|1023&o)))):n+=String.fromCharCode(s)}return n}function e0(e,r){return e?l(C,e,r):""}function r0(e,r,a,i){if(!(0>6}else{if(o<=65535){if(n<=a+2)break;r[a++]=224|o>>12}else{if(n<=a+3)break;r[a++]=240|o>>18,r[a++]=128|o>>12&63}r[a++]=128|o>>6&63}r[a++]=128|63&o}}return r[a]=0,a-t}function a0(e,r,a){r0(e,C,r,a)}function i0(e){for(var r=0,a=0;a>2]=5257216;var b0=[],A0=[],k0=[],l0=[];function _0(){if(y.preRun)for("function"==typeof y.preRun&&(y.preRun=[y.preRun]);y.preRun.length;)e=y.preRun.shift(),b0.unshift(e);var e;u0(b0)}function d0(){if(y.postRun)for("function"==typeof y.postRun&&(y.postRun=[y.postRun]);y.postRun.length;)e=y.postRun.shift(),l0.unshift(e);var e;u0(l0)}var m0=Math.abs,g0=Math.ceil,p0=Math.floor,w0=Math.min,g=0,h0=null,v0=null;function y0(){g++,y.monitorRunDependencies&&y.monitorRunDependencies(g)}function C0(){var e;g--,y.monitorRunDependencies&&y.monitorRunDependencies(g),0==g&&(null!==h0&&(clearInterval(h0),h0=null),v0)&&(e=v0,v0=null,e())}function p(e){throw y.onAbort&&y.onAbort(e),z(e+=""),u(e),X=!0,new A.RuntimeError(e="abort("+e+"). Build with -s ASSERTIONS=1 for more info.")}y.preloadedImages={},y.preloadedAudios={};function E0(e,r){return String.prototype.startsWith?e.startsWith(r):0===e.indexOf(r)}var F0="data:application/octet-stream;base64,";function B0(e){return E0(e,F0)}var D0="file://";function L0(e){return E0(e,D0)}var w,h,v="libflac.wasm";function I0(){try{if(s)return new Uint8Array(s);var e=M(v);if(e)return e;if(t)return t(v);throw"both async and sync fetching of the wasm failed"}catch(e){p(e)}}B0(v)||(c0=v,v=y.locateFile?y.locateFile(c0,f):f+c0);function M0(){var e=(()=>{var r=new Error;if(!r.stack){try{throw new Error}catch(e){r=e}if(!r.stack)return"(no stack trace available)"}return r.stack.toString()})();return y.extraStackTrace&&(e+="\n"+y.extraStackTrace()),e.replace(/\b_Z[\w\d_]+/g,function(e){return e===e?e:e+" ["+e+"]"})}A0.push({func:function(){R0()}});var E={splitPath:function(e){return/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(e).slice(1)},normalizeArray:function(e,r){for(var a=0,i=e.length-1;0<=i;i--){var t=e[i];"."===t?e.splice(i,1):".."===t?(e.splice(i,1),a++):a&&(e.splice(i,1),a--)}if(r)for(;a;a--)e.unshift("..");return e},normalize:function(e){var r="/"===e.charAt(0),a="/"===e.substr(-1);return(e=(e=E.normalizeArray(e.split("/").filter(function(e){return!!e}),!r).join("/"))||r?e:".")&&a&&(e+="/"),(r?"/":"")+e},dirname:function(e){var e=E.splitPath(e),r=e[0],e=e[1];return r||e?r+(e=e&&e.substr(0,e.length-1)):"."},basename:function(e){var r;return"/"===e?"/":-1===(r=e.lastIndexOf("/"))?e:e.substr(r+1)},extname:function(e){return E.splitPath(e)[3]},join:function(){var e=Array.prototype.slice.call(arguments,0);return E.normalize(e.join("/"))},join2:function(e,r){return E.normalize(e+"/"+r)}};function Q0(e){return m[T0()>>2]=e}var F={resolve:function(){for(var e="",r=!1,a=arguments.length-1;-1<=a&&!r;a--){var i=0<=a?arguments[a]:L.cwd();if("string"!=typeof i)throw new TypeError("Arguments to path.resolve must be strings");if(!i)return"";e=i+"/"+e,r="/"===i.charAt(0)}return(r?"/":"")+(e=E.normalizeArray(e.split("/").filter(function(e){return!!e}),!r).join("/"))||"."},relative:function(e,r){function a(e){for(var r=0;r>>0),0!=a&&(r=Math.max(r,256)),a=e.contents,e.contents=new Uint8Array(r),0r)e.contents.length=r;else for(;e.contents.length=e.node.usedBytes)return 0;var f=Math.min(e.node.usedBytes-t,i);if(8>>0)%L.nameTable.length},hashAddNode:function(e){var r=L.hashName(e.parent.id,e.name);e.name_next=L.nameTable[r],L.nameTable[r]=e},hashRemoveNode:function(e){var r=L.hashName(e.parent.id,e.name);if(L.nameTable[r]===e)L.nameTable[r]=e.name_next;else for(var a=L.nameTable[r];a;){if(a.name_next===e){a.name_next=e.name_next;break}a=a.name_next}},lookupNode:function(e,r){var a=L.mayLookup(e);if(a)throw new L.ErrnoError(a,e);for(var a=L.hashName(e.id,r),i=L.nameTable[a];i;i=i.name_next){var t=i.name;if(i.parent.id===e.id&&t===r)return i}return L.lookup(e,r)},createNode:function(e,r,a,i){e=new L.FSNode(e,r,a,i);return L.hashAddNode(e),e},destroyNode:function(e){L.hashRemoveNode(e)},isRoot:function(e){return e===e.parent},isMountpoint:function(e){return!!e.mounted},isFile:function(e){return 32768==(61440&e)},isDir:function(e){return 16384==(61440&e)},isLink:function(e){return 40960==(61440&e)},isChrdev:function(e){return 8192==(61440&e)},isBlkdev:function(e){return 24576==(61440&e)},isFIFO:function(e){return 4096==(61440&e)},isSocket:function(e){return 49152==(49152&e)},flagModes:{r:0,rs:1052672,"r+":2,w:577,wx:705,xw:705,"w+":578,"wx+":706,"xw+":706,a:1089,ax:1217,xa:1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function(e){var r=L.flagModes[e];if(void 0===r)throw new Error("Unknown file open mode: "+e);return r},flagsToPermissionString:function(e){var r=["r","w","rw"][3&e];return 512&e&&(r+="w"),r},nodePermissions:function(e,r){return L.ignorePermissions||(-1===r.indexOf("r")||292&e.mode)&&(-1===r.indexOf("w")||146&e.mode)&&(-1===r.indexOf("x")||73&e.mode)?0:2},mayLookup:function(e){var r=L.nodePermissions(e,"x");return r||(e.node_ops.lookup?0:2)},mayCreate:function(e,r){try{L.lookupNode(e,r);return 20}catch(e){}return L.nodePermissions(e,"wx")},mayDelete:function(e,r,a){var i;try{i=L.lookupNode(e,r)}catch(e){return e.errno}r=L.nodePermissions(e,"wx");if(r)return r;if(a){if(!L.isDir(i.mode))return 54;if(L.isRoot(i)||L.getPath(i)===L.cwd())return 10}else if(L.isDir(i.mode))return 31;return 0},mayOpen:function(e,r){return e?L.isLink(e.mode)?32:L.isDir(e.mode)&&("r"!==L.flagsToPermissionString(r)||512&r)?31:L.nodePermissions(e,L.flagsToPermissionString(r)):44},MAX_OPEN_FDS:4096,nextfd:function(e,r){r=r||L.MAX_OPEN_FDS;for(var a=e=e||0;a<=r;a++)if(!L.streams[a])return a;throw new L.ErrnoError(33)},getStream:function(e){return L.streams[e]},createStream:function(e,r,a){L.FSStream||(L.FSStream=function(){},L.FSStream.prototype={object:{get:function(){return this.node},set:function(e){this.node=e}},isRead:{get:function(){return 1!=(2097155&this.flags)}},isWrite:{get:function(){return 0!=(2097155&this.flags)}},isAppend:{get:function(){return 1024&this.flags}}});var i,t=new L.FSStream;for(i in e)t[i]=e[i];e=t;r=L.nextfd(r,a);return e.fd=r,L.streams[r]=e},closeStream:function(e){L.streams[e]=null},chrdev_stream_ops:{open:function(e){var r=L.getDevice(e.node.rdev);e.stream_ops=r.stream_ops,e.stream_ops.open&&e.stream_ops.open(e)},llseek:function(){throw new L.ErrnoError(70)}},major:function(e){return e>>8},minor:function(e){return 255&e},makedev:function(e,r){return e<<8|r},registerDevice:function(e,r){L.devices[e]={stream_ops:r}},getDevice:function(e){return L.devices[e]},getMounts:function(e){for(var r=[],a=[e];a.length;){var i=a.pop();r.push(i),a.push.apply(a,i.mounts)}return r},syncfs:function(r,a){"function"==typeof r&&(a=r,r=!1),L.syncFSRequests++,1=i.length&&n(null)}i.forEach(function(e){if(!e.type.syncfs)return f(null);e.type.syncfs(e,r,f)})},mount:function(e,r,a){var i,t="/"===a,n=!a;if(t&&L.root)throw new L.ErrnoError(10);if(!t&&!n){n=L.lookupPath(a,{follow_mount:!1});if(a=n.path,L.isMountpoint(i=n.node))throw new L.ErrnoError(10);if(!L.isDir(i.mode))throw new L.ErrnoError(54)}n={type:e,opts:r,mountpoint:a,mounts:[]},r=e.mount(n);return(r.mount=n).root=r,t?L.root=r:i&&(i.mounted=n,i.mount)&&i.mount.mounts.push(n),r},unmount:function(e){e=L.lookupPath(e,{follow_mount:!1});if(!L.isMountpoint(e.node))throw new L.ErrnoError(28);var e=e.node,r=e.mounted,i=L.getMounts(r),r=(Object.keys(L.nameTable).forEach(function(e){for(var r=L.nameTable[e];r;){var a=r.name_next;-1!==i.indexOf(r.mount)&&L.destroyNode(r),r=a}}),e.mounted=null,e.mount.mounts.indexOf(r));e.mount.mounts.splice(r,1)},lookup:function(e,r){return e.node_ops.lookup(e,r)},mknod:function(e,r,a){var i=L.lookupPath(e,{parent:!0}).node,e=E.basename(e);if(!e||"."===e||".."===e)throw new L.ErrnoError(28);var t=L.mayCreate(i,e);if(t)throw new L.ErrnoError(t);if(i.node_ops.mknod)return i.node_ops.mknod(i,e,r,a);throw new L.ErrnoError(63)},create:function(e,r){return L.mknod(e,r=(r=void 0!==r?r:438)&4095|32768,0)},mkdir:function(e,r){return L.mknod(e,r=(r=void 0!==r?r:511)&1023|16384,0)},mkdirTree:function(e,r){for(var a=e.split("/"),i="",t=0;tthis.length-1||e<0))return r=e%this.chunkSize,e=e/this.chunkSize|0,this.getter(e)[r]},t.prototype.setDataGetter=function(e){this.getter=e},t.prototype.cacheLength=function(){var e=new XMLHttpRequest;if(e.open("HEAD",f,!1),e.send(null),!(200<=e.status&&e.status<300||304===e.status))throw new Error("Couldn't load "+f+". Status: "+e.status);var r,i=Number(e.getResponseHeader("Content-length")),a=(r=e.getResponseHeader("Accept-Ranges"))&&"bytes"===r,e=(r=e.getResponseHeader("Content-Encoding"))&&"gzip"===r,t=1048576,n=(a||(t=i),this);n.setDataGetter(function(e){var r=e*t,a=(e+1)*t-1,a=Math.min(a,i-1);if(void 0===n.chunks[e]&&(n.chunks[e]=((e,r)=>{if(r=n.length)return 0;var f=Math.min(n.length-t,i);if(n.slice)for(var o=0;o>2]=i.dev,m[a+4>>2]=0,m[a+8>>2]=i.ino,m[a+12>>2]=i.mode,m[a+16>>2]=i.nlink,m[a+20>>2]=i.uid,m[a+24>>2]=i.gid,m[a+28>>2]=i.rdev,m[a+32>>2]=0,h=[i.size>>>0,(w=i.size,1<=+m0(w)?0>>0:~~+g0((w-(~~w>>>0))/4294967296)>>>0:0)],m[a+40>>2]=h[0],m[a+44>>2]=h[1],m[a+48>>2]=4096,m[a+52>>2]=i.blocks,m[a+56>>2]=i.atime.getTime()/1e3|0,m[a+60>>2]=0,m[a+64>>2]=i.mtime.getTime()/1e3|0,m[a+68>>2]=0,m[a+72>>2]=i.ctime.getTime()/1e3|0,m[a+76>>2]=0,h=[i.ino>>>0,(w=i.ino,1<=+m0(w)?0>>0:~~+g0((w-(~~w>>>0))/4294967296)>>>0:0)],m[a+80>>2]=h[0],m[a+84>>2]=h[1],0},doMsync:function(e,r,a,i,t){e=C.slice(e,e+a);L.msync(r,e,t,a,i)},doMkdir:function(e,r){return"/"===(e=E.normalize(e))[e.length-1]&&(e=e.substr(0,e.length-1)),L.mkdir(e,r,0),0},doMknod:function(e,r,a){switch(61440&r){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}return L.mknod(e,r,a),0},doReadlink:function(e,r,a){var i,t;return a<=0?-28:(e=L.readlink(e),i=Math.min(a,i0(e)),t=d[r+i],a0(e,r,a+1),d[r+i]=t,i)},doAccess:function(e,r){var a;return-8&r?-28:(e=L.lookupPath(e,{follow:!0}).node)?(a="",4&r&&(a+="r"),2&r&&(a+="w"),1&r&&(a+="x"),a&&L.nodePermissions(e,a)?-2:0):-44},doDup:function(e,r,a){var i=L.getStream(a);return i&&L.close(i),L.open(e,r,0,a,a).fd},doReadv:function(e,r,a,i){for(var t=0,n=0;n>2],o=m[r+(8*n+4)>>2],f=L.read(e,d,f,o,i);if(f<0)return-1;if(t+=f,f>2],o=m[r+(8*n+4)>>2],f=L.write(e,d,f,o,i);if(f<0)return-1;t+=f}return t},varargs:void 0,get:function(){return I.varargs+=4,m[I.varargs-4>>2]},getStr:function(e){return e0(e)},getStreamFromFD:function(e){e=L.getStream(e);if(e)return e;throw new L.ErrnoError(8)},get64:function(e,r){return e}};function P0(e,r,a,i){this.parent=e=e||this,this.mount=e.mount,this.mounted=null,this.id=L.nextInode++,this.name=r,this.mode=a,this.node_ops={},this.stream_ops={},this.rdev=i}Object.defineProperties(P0.prototype,{read:{get:function(){return 365==(365&this.mode)},set:function(e){e?this.mode|=365:this.mode&=-366}},write:{get:function(){return 146==(146&this.mode)},set:function(e){e?this.mode|=146:this.mode&=-147}},isFolder:{get:function(){return L.isDir(this.mode)}},isDevice:{get:function(){return L.isChrdev(this.mode)}}}),L.FSNode=P0,L.staticInit();var O0=!1;function S0(e,r,a){a=0>2,a=(3&n)<<6|(f=o.indexOf(e.charAt(c++))),s+=String.fromCharCode(i<<2|t>>4),64!==n&&(s+=String.fromCharCode(r)),64!==f&&(s+=String.fromCharCode(a)),c>>=0;var r=C.length,a=2147483648;if(!(a{try{return b.grow(e-_.byteLength+65535>>>16),o0(b.buffer),1}catch(e){}})(Math.min(a,(0<(n=Math.max(16777216,e,n))%(i=65536)&&(n+=i-n%i),n))))return!0}return!1},fd_close:function(e){try{var r=I.getStreamFromFD(e);return L.close(r),0}catch(e){return void 0!==L&&e instanceof L.ErrnoError||p(e),e.errno}},fd_read:function(e,r,a,i){try{var t=I.getStreamFromFD(e),n=I.doReadv(t,r,a);return m[i>>2]=n,0}catch(e){return void 0!==L&&e instanceof L.ErrnoError||p(e),e.errno}},fd_seek:function(e,r,a,i,t){try{var n=I.getStreamFromFD(e),f=4294967296*a+(r>>>0),o=9007199254740992;return f<=-o||o<=f?-61:(L.llseek(n,f,i),h=[n.position>>>0,(w=n.position,1<=+m0(w)?0>>0:~~+g0((w-(~~w>>>0))/4294967296)>>>0:0)],m[t>>2]=h[0],m[t+4>>2]=h[1],n.getdents&&0==f&&0===i&&(n.getdents=null),0)}catch(e){return void 0!==L&&e instanceof L.ErrnoError||p(e),e.errno}},fd_write:function(e,r,a,i){try{var t=I.getStreamFromFD(e),n=I.doWritev(t,r,a);return m[i>>2]=n,0}catch(e){return void 0!==L&&e instanceof L.ErrnoError||p(e),e.errno}},getTempRet0:function(){return K},memory:b,round:function(e){return 0<=(e=+e)?+p0(e+.5):+g0(e-.5)},setTempRet0:x,table:J},R0=((()=>{var r={env:Y0,wasi_snapshot_preview1:Y0};function a(e,r){e=e.exports;y.asm=e,C0()}function i(e){a(e.instance)}function t(e){return(s||!U&&!c||"function"!=typeof fetch||L0(v)?new Promise(function(e,r){e(I0())}):fetch(v,{credentials:"same-origin"}).then(function(e){if(e.ok)return e.arrayBuffer();throw"failed to load wasm binary file at '"+v+"'"}).catch(I0)).then(function(e){return A.instantiate(e,r)}).then(e,function(e){u("failed to asynchronously prepare wasm: "+e),p(e)})}if(y0(),y.instantiateWasm)try{return y.instantiateWasm(r,a)}catch(e){return u("Module.instantiateWasm callback failed with error: "+e)}s||"function"!=typeof A.instantiateStreaming||B0(v)||L0(v)||"function"!=typeof fetch?t(i):fetch(v,{credentials:"same-origin"}).then(function(e){return A.instantiateStreaming(e,r).then(i,function(e){return u("wasm streaming compile failed: "+e),u("falling back to ArrayBuffer instantiation"),t(i)})})})(),y.___wasm_call_ctors=function(){return(R0=y.___wasm_call_ctors=y.asm.__wasm_call_ctors).apply(null,arguments)}),T0=(y._FLAC__stream_decoder_new=function(){return(y._FLAC__stream_decoder_new=y.asm.FLAC__stream_decoder_new).apply(null,arguments)},y._FLAC__stream_decoder_delete=function(){return(y._FLAC__stream_decoder_delete=y.asm.FLAC__stream_decoder_delete).apply(null,arguments)},y._FLAC__stream_decoder_finish=function(){return(y._FLAC__stream_decoder_finish=y.asm.FLAC__stream_decoder_finish).apply(null,arguments)},y._FLAC__stream_decoder_init_stream=function(){return(y._FLAC__stream_decoder_init_stream=y.asm.FLAC__stream_decoder_init_stream).apply(null,arguments)},y._FLAC__stream_decoder_reset=function(){return(y._FLAC__stream_decoder_reset=y.asm.FLAC__stream_decoder_reset).apply(null,arguments)},y._FLAC__stream_decoder_init_ogg_stream=function(){return(y._FLAC__stream_decoder_init_ogg_stream=y.asm.FLAC__stream_decoder_init_ogg_stream).apply(null,arguments)},y._FLAC__stream_decoder_set_ogg_serial_number=function(){return(y._FLAC__stream_decoder_set_ogg_serial_number=y.asm.FLAC__stream_decoder_set_ogg_serial_number).apply(null,arguments)},y._FLAC__stream_decoder_set_md5_checking=function(){return(y._FLAC__stream_decoder_set_md5_checking=y.asm.FLAC__stream_decoder_set_md5_checking).apply(null,arguments)},y._FLAC__stream_decoder_set_metadata_respond=function(){return(y._FLAC__stream_decoder_set_metadata_respond=y.asm.FLAC__stream_decoder_set_metadata_respond).apply(null,arguments)},y._FLAC__stream_decoder_set_metadata_respond_application=function(){return(y._FLAC__stream_decoder_set_metadata_respond_application=y.asm.FLAC__stream_decoder_set_metadata_respond_application).apply(null,arguments)},y._FLAC__stream_decoder_set_metadata_respond_all=function(){return(y._FLAC__stream_decoder_set_metadata_respond_all=y.asm.FLAC__stream_decoder_set_metadata_respond_all).apply(null,arguments)},y._FLAC__stream_decoder_set_metadata_ignore=function(){return(y._FLAC__stream_decoder_set_metadata_ignore=y.asm.FLAC__stream_decoder_set_metadata_ignore).apply(null,arguments)},y._FLAC__stream_decoder_set_metadata_ignore_application=function(){return(y._FLAC__stream_decoder_set_metadata_ignore_application=y.asm.FLAC__stream_decoder_set_metadata_ignore_application).apply(null,arguments)},y._FLAC__stream_decoder_set_metadata_ignore_all=function(){return(y._FLAC__stream_decoder_set_metadata_ignore_all=y.asm.FLAC__stream_decoder_set_metadata_ignore_all).apply(null,arguments)},y._FLAC__stream_decoder_get_state=function(){return(y._FLAC__stream_decoder_get_state=y.asm.FLAC__stream_decoder_get_state).apply(null,arguments)},y._FLAC__stream_decoder_get_md5_checking=function(){return(y._FLAC__stream_decoder_get_md5_checking=y.asm.FLAC__stream_decoder_get_md5_checking).apply(null,arguments)},y._FLAC__stream_decoder_process_single=function(){return(y._FLAC__stream_decoder_process_single=y.asm.FLAC__stream_decoder_process_single).apply(null,arguments)},y._FLAC__stream_decoder_process_until_end_of_metadata=function(){return(y._FLAC__stream_decoder_process_until_end_of_metadata=y.asm.FLAC__stream_decoder_process_until_end_of_metadata).apply(null,arguments)},y._FLAC__stream_decoder_process_until_end_of_stream=function(){return(y._FLAC__stream_decoder_process_until_end_of_stream=y.asm.FLAC__stream_decoder_process_until_end_of_stream).apply(null,arguments)},y._FLAC__stream_encoder_new=function(){return(y._FLAC__stream_encoder_new=y.asm.FLAC__stream_encoder_new).apply(null,arguments)},y._FLAC__stream_encoder_delete=function(){return(y._FLAC__stream_encoder_delete=y.asm.FLAC__stream_encoder_delete).apply(null,arguments)},y._FLAC__stream_encoder_finish=function(){return(y._FLAC__stream_encoder_finish=y.asm.FLAC__stream_encoder_finish).apply(null,arguments)},y._FLAC__stream_encoder_init_stream=function(){return(y._FLAC__stream_encoder_init_stream=y.asm.FLAC__stream_encoder_init_stream).apply(null,arguments)},y._FLAC__stream_encoder_init_ogg_stream=function(){return(y._FLAC__stream_encoder_init_ogg_stream=y.asm.FLAC__stream_encoder_init_ogg_stream).apply(null,arguments)},y._FLAC__stream_encoder_set_ogg_serial_number=function(){return(y._FLAC__stream_encoder_set_ogg_serial_number=y.asm.FLAC__stream_encoder_set_ogg_serial_number).apply(null,arguments)},y._FLAC__stream_encoder_set_verify=function(){return(y._FLAC__stream_encoder_set_verify=y.asm.FLAC__stream_encoder_set_verify).apply(null,arguments)},y._FLAC__stream_encoder_set_channels=function(){return(y._FLAC__stream_encoder_set_channels=y.asm.FLAC__stream_encoder_set_channels).apply(null,arguments)},y._FLAC__stream_encoder_set_bits_per_sample=function(){return(y._FLAC__stream_encoder_set_bits_per_sample=y.asm.FLAC__stream_encoder_set_bits_per_sample).apply(null,arguments)},y._FLAC__stream_encoder_set_sample_rate=function(){return(y._FLAC__stream_encoder_set_sample_rate=y.asm.FLAC__stream_encoder_set_sample_rate).apply(null,arguments)},y._FLAC__stream_encoder_set_compression_level=function(){return(y._FLAC__stream_encoder_set_compression_level=y.asm.FLAC__stream_encoder_set_compression_level).apply(null,arguments)},y._FLAC__stream_encoder_set_blocksize=function(){return(y._FLAC__stream_encoder_set_blocksize=y.asm.FLAC__stream_encoder_set_blocksize).apply(null,arguments)},y._FLAC__stream_encoder_set_total_samples_estimate=function(){return(y._FLAC__stream_encoder_set_total_samples_estimate=y.asm.FLAC__stream_encoder_set_total_samples_estimate).apply(null,arguments)},y._FLAC__stream_encoder_set_metadata=function(){return(y._FLAC__stream_encoder_set_metadata=y.asm.FLAC__stream_encoder_set_metadata).apply(null,arguments)},y._FLAC__stream_encoder_get_state=function(){return(y._FLAC__stream_encoder_get_state=y.asm.FLAC__stream_encoder_get_state).apply(null,arguments)},y._FLAC__stream_encoder_get_verify_decoder_state=function(){return(y._FLAC__stream_encoder_get_verify_decoder_state=y.asm.FLAC__stream_encoder_get_verify_decoder_state).apply(null,arguments)},y._FLAC__stream_encoder_get_verify=function(){return(y._FLAC__stream_encoder_get_verify=y.asm.FLAC__stream_encoder_get_verify).apply(null,arguments)},y._FLAC__stream_encoder_process=function(){return(y._FLAC__stream_encoder_process=y.asm.FLAC__stream_encoder_process).apply(null,arguments)},y._FLAC__stream_encoder_process_interleaved=function(){return(y._FLAC__stream_encoder_process_interleaved=y.asm.FLAC__stream_encoder_process_interleaved).apply(null,arguments)},y.___errno_location=function(){return(T0=y.___errno_location=y.asm.__errno_location).apply(null,arguments)}),U0=y.stackSave=function(){return(U0=y.stackSave=y.asm.stackSave).apply(null,arguments)},x0=y.stackRestore=function(){return(x0=y.stackRestore=y.asm.stackRestore).apply(null,arguments)},z0=y.stackAlloc=function(){return(z0=y.stackAlloc=y.asm.stackAlloc).apply(null,arguments)},j0=y._malloc=function(){return(j0=y._malloc=y.asm.malloc).apply(null,arguments)},H0=(y._free=function(){return(y._free=y.asm.free).apply(null,arguments)},y.__growWasmMemory=function(){return(H0=y.__growWasmMemory=y.asm.__growWasmMemory).apply(null,arguments)});y.dynCall_iii=function(){return(y.dynCall_iii=y.asm.dynCall_iii).apply(null,arguments)},y.dynCall_ii=function(){return(y.dynCall_ii=y.asm.dynCall_ii).apply(null,arguments)},y.dynCall_iiii=function(){return(y.dynCall_iiii=y.asm.dynCall_iiii).apply(null,arguments)},y.dynCall_jiji=function(){return(y.dynCall_jiji=y.asm.dynCall_jiji).apply(null,arguments)},y.dynCall_viiiiii=function(){return(y.dynCall_viiiiii=y.asm.dynCall_viiiiii).apply(null,arguments)},y.dynCall_iiiii=function(){return(y.dynCall_iiiii=y.asm.dynCall_iiiii).apply(null,arguments)},y.dynCall_viiiiiii=function(){return(y.dynCall_viiiiiii=y.asm.dynCall_viiiiiii).apply(null,arguments)},y.dynCall_viiii=function(){return(y.dynCall_viiii=y.asm.dynCall_viiii).apply(null,arguments)},y.dynCall_viii=function(){return(y.dynCall_viii=y.asm.dynCall_viii).apply(null,arguments)};y.ccall=q,y.cwrap=function(e,r,a,i){var t=(a=a||[]).every(function(e){return"number"===e});return"string"!==r&&t&&!i?Z(e):function(){return q(e,r,a,arguments)}},y.setValue=W;y.getValue=function(e,r,a){switch(r="*"===(r=r||"i8").charAt(r.length-1)?"i32":r){case"i1":case"i8":return d[e>>0];case"i16":return t0[e>>1];case"i32":case"i64":return m[e>>2];case"float":return n0[e>>2];case"double":return f0[e>>3];default:p("invalid type for getValue: "+r)}return null};function K0(e){function r(){V0||(V0=!0,y.calledRun=!0,X)||(y.noFSInit||L.init.initialized||L.init(),B.init(),u0(A0),L.ignorePermissions=!1,u0(k0),y.onRuntimeInitialized&&y.onRuntimeInitialized(),d0())}0{for(var r,a=[],i=0;i<16;++i)(r=(r=(r=y.getValue(e+i,"i8"))<0?256+r:r).toString(16)).length<2&&(r="0"+r),a.push(r);return a.join("")})(e+40)}}function J0(e,r){var a=y.getValue(e,"i32"),i=y.getValue(e+4,"i32"),t=y.getValue(e+8,"i32"),n=y.getValue(e+12,"i32"),f=y.getValue(e+16,"i32"),o=y.getValue(e+20,"i32"),s=y.getValue(e+24,"i32"),c=y.getValue(e+24,"i64"),s=0===o?s:c,c=0===o?"frames":"samples",o=y.getValue(e+36,"i8");if(r&&r.analyseSubframes)for(var u={offset:40},b=[],A=0;A{var t,n=y.getValue(e+r.offset,"i32");switch(r.offset+=4,n){case 0:t={value:y.getValue(e+r.offset,"i32")},r.offset+=284;break;case 1:t=y.getValue(e+r.offset,"i32"),r.offset+=284;break;case 2:t=X0(e,r,a,!1,i);break;case 3:t=X0(e,r,a,!0,i)}var f=r.offset,f=y.getValue(e+f,"i32");return r.offset+=4,{type:n,data:t,wastedBits:f}})(e,u,a,r));return{blocksize:a,sampleRate:i,channels:t,channelAssignment:n,bitsPerSample:f,number:s,numberType:c,crc:o,subframes:b}}function X0(e,r,a,i,t){var n=r.offset,f={order:-1,contents:{parameters:[],rawBits:[]}},o=y.getValue(e,"i32"),s=y.getValue(e+(n+=4),"i32"),c=1<<(f.order=s),u=f.contents.parameters,b=f.contents.rawBits,s=y.getValue(e+(n+=4),"i32"),A=y.getValue(s,"i32"),k=y.getValue(s+4,"i32");f.contents.capacityByOrder=y.getValue(s+8,"i32");for(var l=0;l{var a,i=y.getValue(e+22,"i8"),t=y.getValue(e+23,"i8"),n=[],r={offset:y.getValue(e,"i64"),number:255&y.getValue(e+8,"i8"),isrc:$0(e+9,13,r),type:1&i?"NON_AUDIO":"AUDIO",pre_emphasis:!!(2&i),num_indices:t,indices:n};if(0{for(var r=y.getValue(e,"i32"),a=y.getValue(e+4,"i32"),i=[],t=0;t{for(var r,a,i=y.getValue(e,"i32"),t=[],i=$0(y.getValue(e+4,"i32"),i,t),n=y.getValue(e+8,"i32"),f=[],o=y.getValue(e+12,"i32"),s=0;s { + lz4BlockWASM = instance; + + q.ready = true; + q.loading = false; + q.compress = function( input, offset ) { + if (!lz4BlockWASM) { + if (input instanceof ArrayBuffer) + return new Uint8Array(input); + else + return input; + } + + return lz4BlockWASM.encodeBlock(input, 0); + }; + q.decompress = function( input, offset, size ) { + if (!lz4BlockWASM) { + if (input instanceof ArrayBuffer) + return new Uint8Array(input); + else + return input; + } + + return lz4BlockWASM.decodeBlock(input, 0, size); + }; + + callback && callback (); + }); + // --- + } + } + }; + + var compression = 'l4z'; + + function SaveLocal ( app ) { + var q = this; + q.on = false; + + this.Init = function ( callback ) { + if (q.on) { + callback && callback (); + return ; + } + + if (!window.indexedDB) { + callback && callback ('err'); + return ; + } + + var request = indexedDB.open (db_name, db_version); + + request.onerror = function(e) { + callback && callback ('err'); + // console.error('Unable to open database.'); + }; + + request.onupgradeneeded = function(e) { + var db = e.target.result; + db.createObjectStore('sessions', {keyPath:'id'}); + }; + + request.onsuccess = function(e) { + db = e.target.result; + + db.onerror = function( e ) { + console.log( e ); + }; + + setTimeout(function() { + db_ready = true; + q.on = true; + + callback && callback (); + app.fireEvent ('DidOpenDB', q); + },120); + }; + }; + + this.SaveSession = function ( buffer, id, name ) { + var q = this; + + var comp = compressors[ compression ]; + if (!comp.loading && !comp.ready) { + comp.init (function() { + q.SaveSession (buffer, id, name); + }); + + return ; + } + + var chans = buffer.numberOfChannels; + var arr_buffs = []; + var arr_buffs2 = []; + var arr; + var tmp; + + var sample_rate = buffer.sampleRate; + + for (var i = 0; i < chans; ++i) { + arr = buffer.getChannelData ( i ); + + arr_buffs2.push (arr.buffer.byteLength); + tmp = comp.compress ( arr.buffer, 0); + arr_buffs.push ( tmp.buffer.slice (tmp.byteOffset, tmp.byteLength + tmp.byteOffset)); + } + + tmp = null; + + var ob = { + id : id, + name: name, + created: new Date().getTime(), + data: arr_buffs, + data2: arr_buffs2, + durr: buffer.duration.toFixed(3)/1, + chans: chans, + comp: compression, + thumb: PKAudioEditor.engine.GetWave (buffer), + samplerate: sample_rate + }; + + var trans = db.transaction(['sessions'], 'readwrite'); + var addReq = trans.objectStore('sessions').add(ob); + + addReq.onerror = function(e) { + app.fireEvent ('ErrorDB', e); + + console.log('error storing data'); + console.error(e); + }; + + trans.oncomplete = function ( e ) { + app.fireEvent ('DidStoreDB', ob, e ); + // console.log( 'data stored', id, e ); + }; + }; + + this.GetSession = function ( id, callback ) { + var trans = db.transaction(['sessions'], 'readonly'); + //hard coded id + var req = trans.objectStore('sessions').get(id); + + req.onsuccess = function(e) { + // console.log( e.target.result ); + + + var record = e.target.result; + + if (record && record.comp) + { + var comp = compressors[ compression ]; + if (!comp.loading && !comp.ready) { + comp.init (function() { + + var data_arr = []; + var tmp = null; + + for (var i = 0; i < record.data.length; ++i) { + tmp = comp.decompress (record.data[i], 0, record.data2[i]); + data_arr.push ( + tmp.buffer.slice (tmp.byteOffset, tmp.byteLength + tmp.byteOffset) + ); + } + + tmp = null; + record.data = data_arr; + + callback && callback ( record ); + }); + + return ; + } + + var data_arr = []; + var tmp = null; + + for (var i = 0; i < record.data.length; ++i) { + tmp = comp.decompress (record.data[i], 0, record.data2[i]); + data_arr.push ( + tmp.buffer.slice (tmp.byteOffset, tmp.byteLength + tmp.byteOffset) + ); + } + + tmp = null; + record.data = data_arr; + } + + callback && callback ( record ); + }; + }; + + this.DelSession = function ( id, callback ) { + var trans = db.transaction(['sessions'], 'readwrite'); + + var req = trans.objectStore('sessions').delete (id); + req.onsuccess = function (e) { + callback && callback ( id ); + }; + }; + + this.ListSessions = function ( callback ) { + var trans = db.transaction(['sessions'], 'readonly'); + var object_store = trans.objectStore('sessions'); + var req = object_store.openCursor(); + var ret = []; + + req.onerror = function(event) { + console.err("error fetching data"); + }; + req.onsuccess = function(event) { + var cursor = event.target.result; + if (cursor) { + var key = cursor.primaryKey; + var value = cursor.value; + + ret.push (value); + cursor.continue(); + } + else { + var rr = ret.sort(function compare( a, b ) { + if ( a.created > b.created ){ + return -1; + } + if ( a.created < b.created ){ + return 1; + } + return 0; + }); + + callback && callback (rr); + // no more results + } + }; + }; + // --- + }; + + PKAudioEditor._deps.fls = SaveLocal; + +})( window, document, PKAudioEditor ); \ No newline at end of file diff --git a/audiomass-editor/src/lz4-block-codec-wasm.js b/audiomass-editor/src/lz4-block-codec-wasm.js new file mode 100644 index 0000000..7ec65c3 --- /dev/null +++ b/audiomass-editor/src/lz4-block-codec-wasm.js @@ -0,0 +1,194 @@ +/******************************************************************************* + + lz4-block-codec-wasm.js + A javascript wrapper around a WebAssembly implementation of + LZ4 block format codec. + Copyright (C) 2018 Raymond Hill + + BSD-2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Home: https://github.com/gorhill/lz4-wasm + + I used the same license as the one picked by creator of LZ4 out of respect + for his creation, see https://lz4.github.io/lz4/ + +*/ + +/* global WebAssembly */ + +'use strict'; + +/******************************************************************************/ + +(function(context) { // >>>> Start of private namespace + +/******************************************************************************/ + +let wd = (function() { + let url = document.currentScript.src; + let match = /[^\/]+$/.exec(url); + return match !== null ? + url.slice(0, match.index) : + ''; +})(); + +let growMemoryTo = function(wasmInstance, byteLength) { + let lz4api = wasmInstance.exports; + let neededByteLength = lz4api.getLinearMemoryOffset() + byteLength; + let pageCountBefore = lz4api.memory.buffer.byteLength >>> 16; + let pageCountAfter = (neededByteLength + 65535) >>> 16; + if ( pageCountAfter > pageCountBefore ) { + lz4api.memory.grow(pageCountAfter - pageCountBefore); + } + return lz4api.memory.buffer; +}; + +let encodeBlock = function(wasmInstance, inputArray, outputOffset) { + let lz4api = wasmInstance.exports; + let mem0 = lz4api.getLinearMemoryOffset(); + let hashTableSize = 65536 * 4; + let inputSize = inputArray.byteLength; + if ( inputSize >= 0x7E000000 ) { throw new RangeError(); } + let memSize = + hashTableSize + + inputSize + + outputOffset + lz4api.lz4BlockEncodeBound(inputSize); + let memBuffer = growMemoryTo(wasmInstance, memSize); + let hashTable = new Int32Array(memBuffer, mem0, 65536); + hashTable.fill(-65536, 0, 65536); + let inputMem = new Uint8Array(memBuffer, mem0 + hashTableSize, inputSize); + inputMem.set(inputArray); + let outputSize = lz4api.lz4BlockEncode( + mem0 + hashTableSize, + inputSize, + mem0 + hashTableSize + inputSize + outputOffset + ); + if ( outputSize === 0 ) { return; } + let outputArray = new Uint8Array( + memBuffer, + mem0 + hashTableSize + inputSize, + outputOffset + outputSize + ); + return outputArray; +}; + +let decodeBlock = function(wasmInstance, inputArray, inputOffset, outputSize) { + let inputSize = inputArray.byteLength; + let lz4api = wasmInstance.exports; + let mem0 = lz4api.getLinearMemoryOffset(); + let memSize = inputSize + outputSize; + let memBuffer = growMemoryTo(wasmInstance, memSize); + let inputArea = new Uint8Array(memBuffer, mem0, inputSize); + inputArea.set(inputArray); + outputSize = lz4api.lz4BlockDecode( + mem0 + inputOffset, + inputSize - inputOffset, + mem0 + inputSize + ); + if ( outputSize === 0 ) { return; } + return new Uint8Array(memBuffer, mem0 + inputSize, outputSize); +}; + +/******************************************************************************/ + +context.LZ4BlockWASM = function() { + this.lz4wasmInstance = undefined; +}; + +context.LZ4BlockWASM.prototype = { + flavor: 'wasm', + + init: function() { + if ( + typeof WebAssembly !== 'object' || + typeof WebAssembly.instantiateStreaming !== 'function' + ) { + this.lz4wasmInstance = null; + } + if ( this.lz4wasmInstance === null ) { + return Promise.reject(); + } + if ( this.lz4wasmInstance instanceof WebAssembly.Instance ) { + return Promise.resolve(this.lz4wasmInstance); + } + if ( this.lz4wasmInstance === undefined ) { + this.lz4wasmInstance = WebAssembly.instantiateStreaming( + fetch(wd + 'lz4-block-codec.wasm', { mode: 'same-origin' }) + ).then(result => { + this.lz4wasmInstance = undefined; + this.lz4wasmInstance = result && result.instance || null; + if ( this.lz4wasmInstance !== null ) { return this; } + return null; + }); + this.lz4wasmInstance.catch(( ) => { + this.lz4wasmInstance = null; + return null; + }); + } + return this.lz4wasmInstance; + }, + + reset: function() { + this.lz4wasmInstance = undefined; + }, + + bytesInUse: function() { + return this.lz4wasmInstance instanceof WebAssembly.Instance ? + this.lz4wasmInstance.exports.memory.buffer.byteLength : + 0; + }, + + encodeBlock: function(input, outputOffset) { + if ( this.lz4wasmInstance instanceof WebAssembly.Instance === false ) { + throw new Error('LZ4BlockWASM: not initialized'); + } + if ( input instanceof ArrayBuffer ) { + input = new Uint8Array(input); + } else if ( input instanceof Uint8Array === false ) { + throw new TypeError(); + } + return encodeBlock(this.lz4wasmInstance, input, outputOffset); + }, + + decodeBlock: function(input, inputOffset, outputSize) { + if ( this.lz4wasmInstance instanceof WebAssembly.Instance === false ) { + throw new Error('LZ4BlockWASM: not initialized'); + } + if ( input instanceof ArrayBuffer ) { + input = new Uint8Array(input); + } else if ( input instanceof Uint8Array === false ) { + throw new TypeError(); + } + return decodeBlock(this.lz4wasmInstance, input, inputOffset, outputSize); + } +}; + +/******************************************************************************/ + +})(this || self); // <<<< End of private namespace + +/******************************************************************************/ \ No newline at end of file diff --git a/audiomass-editor/src/lz4-block-codec.wasm b/audiomass-editor/src/lz4-block-codec.wasm new file mode 100644 index 0000000..c57b079 Binary files /dev/null and b/audiomass-editor/src/lz4-block-codec.wasm differ diff --git a/audiomass-editor/src/lzma.js b/audiomass-editor/src/lzma.js new file mode 100644 index 0000000..a9cf389 --- /dev/null +++ b/audiomass-editor/src/lzma.js @@ -0,0 +1,169 @@ +/******************************************************************************* + + lz4-block-codec-any.js + A wrapper to instanciate a wasm- and/or js-based LZ4 block + encoder/decoder. + Copyright (C) 2018 Raymond Hill + + BSD-2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Home: https://github.com/gorhill/lz4-wasm + + I used the same license as the one picked by creator of LZ4 out of respect + for his creation, see https://lz4.github.io/lz4/ + +*/ + +'use strict'; + +/******************************************************************************/ + +(function(context) { // >>>> Start of private namespace + +/******************************************************************************/ + +let wd = (function() { + let url = document.currentScript.src; + let match = /[^\/]+$/.exec(url); + return match !== null ? + url.slice(0, match.index) : + ''; +})(); + +let removeScript = function(script) { + if ( !script ) { return; } + if ( script.parentNode === null ) { return; } + script.parentNode.removeChild(script); +}; + +let createInstanceWASM = function() { + if ( context.LZ4BlockWASM instanceof Function ) { + let instance = new context.LZ4BlockWASM(); + return instance.init().then(( ) => { return instance; }); + } + if ( context.LZ4BlockWASM === null ) { + return Promise.resolve(null); + } + return new Promise((resolve, reject) => { + let script = document.createElement('script'); + script.src = wd + 'lz4-block-codec-wasm.js'; + script.addEventListener('load', ( ) => { + if ( context.LZ4BlockWASM instanceof Function === false ) { + context.LZ4BlockWASM = null; + context.LZ4BlockWASM = undefined; + resolve(null); + } else { + let instance = new context.LZ4BlockWASM(); + instance.init() + .then(( ) => { + resolve(instance); + }) + .catch(error => { + reject(error); + }); + } + }); + script.addEventListener('error', ( ) => { + context.LZ4BlockWASM = null; + resolve(null); + }); + document.head.appendChild(script); + removeScript(script); + }); +}; + +let createInstanceJS = function() { + if ( context.LZ4BlockJS instanceof Function ) { + let instance = new context.LZ4BlockJS(); + return instance.init().then(( ) => { return instance; }); + } + if ( context.LZ4BlockJS === null ) { + return Promise.resolve(null); + } + return new Promise((resolve, reject) => { + let script = document.createElement('script'); + script.src = wd + 'lz4-block-codec-js.js'; + script.addEventListener('load', ( ) => { + if ( context.LZ4BlockJS instanceof Function === false ) { + context.LZ4BlockJS = null; + resolve(null); + } else { + let instance = new context.LZ4BlockJS(); + instance.init() + .then(( ) => { + resolve(instance); + }) + .catch(error => { + reject(error); + }); + } + }); + script.addEventListener('error', ( ) => { + context.LZ4BlockJS = null; + resolve(null); + }); + document.head.appendChild(script); + removeScript(script); + }); +}; + +/******************************************************************************/ + +context.lz4BlockCodec = { + createInstance: function(flavor) { + let instantiator; + if ( flavor === 'wasm' ) { + instantiator = createInstanceWASM; + } else if ( flavor === 'js' ) { + instantiator = createInstanceJS; + } else { + instantiator = createInstanceWASM || createInstanceJS; + } + return (instantiator)() + .then(instance => { + if ( instance ) { return instance; } + if ( flavor === undefined ) { + return createInstanceJS(); + } + return null; + }) + .catch(( ) => { + if ( flavor === undefined ) { + return createInstanceJS(); + } + return null; + }); + }, + reset: function() { + context.LZ4BlockWASM = undefined; + context.LZ4BlockJS = undefined; + } +}; + +/******************************************************************************/ + +})(this || self); // <<<< End of private namespace \ No newline at end of file diff --git a/audiomass-editor/src/main.css b/audiomass-editor/src/main.css new file mode 100755 index 0000000..729761d --- /dev/null +++ b/audiomass-editor/src/main.css @@ -0,0 +1,2018 @@ +@font-face { + font-family: 'icomoon'; + src: url('fonts/icomoon.eot'); + src: url('fonts/icomoon.eot#iefix') format('embedded-opentype'), + url('fonts/icomoon.ttf') format('truetype'), + url('fonts/icomoon.woff') format('woff'), + url('fonts/icomoon.svg#icomoon') format('svg'); + font-weight: normal; + font-style: normal; +} + +body{ + padding:0; + margin:0; + font-size:13px; + font-family:Helvetica, Arial, sans-serif; + color:#eee; + text-decoration:none; + -webkit-tap-highlight-color:rgba(0,0,0,0); +} + +/*html{ + -ms-text-size-adjust:100%; + -webkit-text-size-adjust:100% +}*/ + +body,html{height:100%;background:#111; + /*overflow:hidden*/ +} + +.pk_noselect{ + -webkit-touch-callout: none; + -ms-user-select: none; + user-select: none +} + +.pk_app{ + width:100%; + height:100%; + + /*min-width:560px*/ +} + +/** HEADER **/ +.pk_hdr{ + z-index:7; + padding:0 5px; + height:24px; + position:relative; + border-bottom:1px solid #454545 +} + +.pk_hdr .pk_btn{ + float:left; + margin:4px 18px 0 18px; + position:relative; + min-width:40px; + border-radius:10px; + text-align:center +} +.pk_btn button{ + padding: 0 12px; + border:0; + outline:0; + color:inherit; + background:transparent; + cursor: pointer; + text-decoration:inherit; + text-shadow:inherit; + white-space:nowrap +} + +.pk_hdr .pk_btn:hover{ + background:#eee; + color:#111 +} + +.pk_hdr .pk_btn.pk_act{ + background:#bbb; + color:#000; + text-decoration:underline; + text-shadow: 0 1px 2px white; +} + +.pk_hdr .pk_btn .pk_menu{ + position:absolute; + min-width:100px; + min-height:20px; + top:20px; + border-radius:10px; + background:#eee; + opacity:0; + z-index:-1; + visibility:hidden; + padding: 8px 0px; + display:none; + transition:opacity 200ms +} + +.pk_hdr .pk_btn.pk_vis .pk_menu{ + display:block; +} +.pk_hdr .pk_btn.pk_act .pk_menu{ + z-index:5; + opacity:1; + visibility:visible; + display:block; +} + +.pk_hdr .pk_btn .pk_menu_el .pk_act{ + background:lightblue; +} + +/*.pk_hdr .pk_btn i{ + margin-left: 4px; + font-style: normal; + color: #555 +}*/ + + +.pk_hdr .pk_btn .pk_shrtct{ + color: #555; + margin-left: 24px; + display: inline-block; + font-size: 0.92em; + text-align: right; +} + +.pk_hdr .pk_btn .pk_menu_el button{ + margin: 2px 0; + display: block; + width: 100%; + text-align: left; + padding: 2px 12px; + display:flex; + justify-content: space-between; +} +/** ENDOF HEADER **/ + + +/** TOOL BAR **/ +.pk_tb{ + height:48px; + background: #363636; + position: relative; + z-index: 6; + padding:8px 0px 8px 14px; + border-bottom:1px solid #000; + min-width:560px; + text-rendering: optimizeSpeed; +} + + +.pk_total_dur, +.pk_hover_dur{ + color:#99c2c6; + font-size:14px; + position:absolute; + right:10px; + top:6px; +} + +.pk_mload{ + width: 200px; + margin: 0 auto; + height: 3px; + position: relative; + background: #111; + overflow: hidden; + margin-top: 25px; +} + +.pk_mload > div:before { + content:" "; + /*transition:all 300ms ease-in-out;*/ + background:#ccc; + height:100%; + width:100%; + margin-left:0; + z-index:1; + left:0; + position: absolute; + transform: scaleX(0) translate3d(0,0,0); + transform-origin: 0 0 0; + will-change: transform; +} + +.pk_act .pk_mload > div:before { + animation-name: pk_loader_anim; + animation-duration: 1.8s; + animation-iteration-count: infinite; +} + +.pk_prc{ + margin-top: 20px; + font-size: 14px; +} + +.pk_prc span{ + margin-right:10px; + padding-bottom: 7px; + text-align: center; +} +.pk_prc button{ + border-radius: 3px; + border:1px solid #eee; + background: transparent; + color: #eee; + padding: 4px 12px; + outline:0; +} + +.pk_hover_dur{ + top:26px; +} + +.pk_inpfile{ + visibility: hidden; + width: 1px; + height: 1px; + overflow:hidden; + position:absolute; + z-index:-1; +} + +button{color:#040404;-webkit-tap-highlight-color:rgba(0,0,0,0)} +a{cursor:pointer;color:#99c2c6;-webkit-tap-highlight-color:rgba(0,0,0,0)} + +.pk_tmpMsg{ + position: absolute; + left: 50%; + top: 50%; + margin-left: -170px; + width: 340px; + z-index: 6; + margin-top: -40px; + height: 100px; + font-size: 18px; + color: #ddd; + text-align: center; + text-shadow: 0 0 1px black; + line-height:32px; +} + +.pk_tmpMsg2{ + position: fixed; + background:rgba(0,0,0,0.6); + z-index: 10; + left:0;right:0; + top:0;bottom:0; + text-align:center; + font-size: 16px; + justify-content: center; + flex-direction: column; + display:none; + cursor:progress !important; +} + +.pk_tmpMsg2.pk_act{display:flex} + +.pk_timecontainer{ + float: left; + width: 236px; + margin-right:12px; + border: 1px solid #777; + background: black; + position:relative; + height: 46px; + color: #eee; + border-radius: 3px; + contain:strict; +} + +.pk_mob .pk_timecontainer{ + cursor:pointer +} +.pk_timing{ + display: block; + position: absolute; + padding:9px 0 0 14px; + letter-spacing: 1px; + font-size: 29px; + text-align: left; + z-index: 2; +} + +.pk_timingcnv{ + display: block; + position: absolute; + z-index: 2; + left:6px; +} + +.pk_btngroup{float:left;} + +.pk_selection, +.pk_ctns, +.pk_transport{ + float:left; + margin-right:12px; + min-width:340px; + padding: 0 2px; + height:46px; + border:1px solid #777; + border-radius: 3px; +} +.pk_selection{margin-right:0} +.pk_ctns{ + min-width:40px; +} + +.pk_tb .pk_btn{ + font-family: 'icomoon'; + position: relative; + font-size: 1.32em; + display: inline-block; + border-radius: 3px; + width: 38px; + height: 38px; + margin: 4px 3px; + text-align: center; + line-height: 25px; + border: none; + outline: 0; + padding:0; +} +.pk_tb .pk_btn:hover{ + box-shadow:0 0 6px #7799ff; +} +.pk_tb .pk_btn:active{ + box-shadow: inset 0 0 10px #262626; +} + +.pk_ftr .pk_btn span, +.pk_tb .pk_btn span { + display: block; + -ms-user-select: none; + user-select: none; + visibility: hidden; + line-height: 26px; + opacity: 0; + pointer-events: none; + font-family: Arial, sans-serif; + position: absolute; + bottom: -31px; + left: 50%; + transform:translate(-50%, 0); + white-space: nowrap; + background: #000; + font-size: 11px; + font-weight:normal; + padding: 0 6px; + border-radius: 3px; + transition: opacity 320ms 296ms; + color:#eee; + z-index:6; + letter-spacing:normal; +} + +.pk_ftr .pk_btn.pk_inact:hover span, +.pk_tb .pk_btn.pk_inact:hover span{ + opacity:0; + visibility:hidden; +} + +.pk_ftr .pk_btn:hover span, +.pk_tb .pk_btn:hover span{ + visibility:visible; + opacity:1; +} + +.pk_mob .pk_ftr .pk_btn span, +.pk_mob .pk_tb .pk_btn span{ + visibility:hidden; + display:none; +} +.pk_mob .pk_tb .pk_btn:hover{ + box-shadow:none; +} +/** ENDOF TOOLBAR **/ + + +/** AUDIOVIEW **/ +.pk_av_cont{ + position:relative; + touch-action:none; +} +.pk_av{ + clear:both; + width:100%; + width:calc(100% - 64px); + margin:0 auto; + contain: content; + /*height:calc(100% - 168px);*/ + + background:#000; + position:relative; + overflow:hidden; + margin-left: 48px; /*left menu*/ +} + +.pk_av wave{ + cursor:text; +} + +#pk_prgwv{ + position: absolute; + z-index: 3; + left: 0; + top: 0; + bottom: 0; + background:#ff8c35; + width:1px; + display: none; + /*box-sizing: 'border-box'*/ + transform: translate3d(0,0,0); + pointer-events:none; +} + +/* +#pk_prgwv:after{ + content: ''; + display:block; + background:#ff8c35; + width:1px; + height:100%; +}*/ + +/*.pk_mob .pk_av{ + width:calc(100% - 28px); +}*/ +/** ENDOF AUDIOVIEW **/ + +.pk_selection .pk_sellist{ + color: #e1e1e1; + margin:5px; + width:346px; +} +.pk_sellist .pk_title{ + line-height:35px; + float:left; +} + +.pk_selection .pk_sellist div{ + float:left; + margin:0 10px; + width:40px; + text-align:center; +} +.pk_selection .title{ + display:block; + line-height: 18px; +} + +.pk_selection .pk_dat{ + background:#383838; + padding:2px 5px; + color:#99c2c6; + min-width: 14px; + display: inline-block +} + +.pk_btn.icon-clearsel{ + font-family:Helvetica, Arial, sans-serif; + width: 92px; + font-size: 12px; + line-height: 20px; + height: 30px; + padding: 0; + margin: 3px 0 0 12px; +} + + +.pk_ftr{padding:2px 14px 8px 14px;} +.pk_volpar{ + position:relative; + width:100%; + height:5px; + background:#000; + border:1px solid #222; + background:green; + overflow:hidden; + background: linear-gradient(to right, #99c2c6 0%,#6ecc87 54%,#d6af22 85%,#d15110 100%); + background: -webkit-linear-gradient(left, #99c2c6 0%,#6ecc87 54%,#d6af22 85%,#d15110 100%); +} +.pk_volpar:last-child{ + border-top:2px solid #222; +} +.pk_vol{ + position:absolute; + right:0; + top:0; + width:100%; + bottom:0; + z-index:1; + pointer-events:none; + background:black; + transform:translate3d(0,0,0); +} + +.pk_peaker{ + position:absolute; + height:100%; + right:0; + top:0; + z-index:2; + width:15px; + border-left: 2px solid #282828; + background:#111; +} +.pk_peaker.pk_act{ + background:red +} +.pk_markers{ + font-size: 10px; + position: relative; + width: 100%; + border-right: 12px solid transparent; + text-align: left; + color: #858585; + box-sizing: border-box; + margin-top:4px; + font-weight:lighter; + letter-spacing: 0.5px; +} +.pk_mark1{ + display:inline-block; + width:2.777%; +} + +.pk_mark1:last-child{ + position:absolute; + text-align:right; + right:0px; +} + + +.pk_zoombtn{ + float: left; + /*height: 26px;*/ + padding-right: 4px; + position:relative; +} + +.pk_zoombtn button{ + border-radius: 3px; + border:1px solid #246e6e; + height: 18px; + margin-right: 6px; + padding: 0; + width: 26px; + line-height: 16px; + cursor: pointer; + color: #246e6e; + background: #000; + font-size: 12px; + outline: 0; + font-weight:bold; + font-family:Arial, serif; +} + +.pk_zoombtn .pk_zoom_out_v, +.pk_zoombtn .pk_zoom_in_v{ + position:absolute; + left:0; + top:-50px; +} + +.pk_zoombtn .pk_zoom_in_v span, +.pk_zoombtn .pk_zoom_out_v span{ + margin-left:40px; +} +.pk_zoombtn .pk_zoom_out_v{ + top:-26px; +} + +/* +.pk_mob .pk_zoombtn{ + display:none +}*/ + +.pk_mob .pk_zoom_in_v, +.pk_mob .pk_zoom_out_v{ + display:none +} + +.pk_panner{ + position: absolute; + width: 48px; + height: 100%; + left: 0; + top: 0; +} + +.pk_mono .pk_panner{ + display:none !important; +} + +.pk_pan_left{ + position: absolute; + left:14px; + top: 0%; + height:50%; +} +.pk_pan_right{ + position: absolute; + left:14px; + top: 50%; + height:50%; +} + +.pk_pan_btn { + position: absolute; + left: 20%; + display: block; + padding: 0; + margin: 0; + font-size:10px; + word-break: break-all; + border: 0; + white-space: nowrap; + top: 30%; + border-radius: 3px; + width: 24px; + text-align: center; + outline:0; + height: 40%; + color: #2a8472; + background: #040405; +} +.pk_pan_btn strong{font-size:12px;display:block} + +.pk_pan_btn:active{ + background: #000; + color: #46b49d; +} + + + +.pk_contextMenu{ + position:absolute; + z-index:99999; +} + +.pk_contextMenu div{ position:relative; } + +.pk_contextMenu{ + background: #111; + border: 1px solid #444; + font-family:Arial, serif, sans-serif; + font-size:14px; + margin: 1px 0 0; + min-width: 150px; + padding: 4px 0; + color:#111; + z-index: 8; + border-radius:3px; + box-shadow: 0 2px 12px rgba(138, 58, 138, 0.5); + background-clip: padding-box; +} +.pk_contextMenu a, .pk_contextMenu a:hover{ + clear: both; + color: #eee; + display: block; + font-weight: normal; + line-height: 18px; + margin:2px 5px; + padding: 5px 8px; + font-size:13px; + white-space: nowrap; + cursor:pointer; + font-family:Arial, serif, sans-serif; + font-weight:normal; + transition: all 110ms; +} +.pk_contextMenu a:hover{ + color:#99c2c6; + line-height: 18px; + text-decoration: none; +} + + +/* if max height < ... hide vertical buttons and position to 0... */ + +.pk_wavescroll { + margin-bottom:10px; + height: 14px; + border: 1px solid #222; + background: #000; + overflow:hidden; + position:relative; + contain:strict; +} + +.pk_wavedrag.pk_drag{ + cursor:grabbing; + cursor:-webkit-grabbing; +} +.pk_wavedrag{ + cursor:pointer; + cursor:grab; + cursor:-webkit-grab; + border-radius:4px; + transform:translate3d(0,0,0); +} +.pk_wavedrag.pk_inact{ + cursor:default; + border-radius:0; +} +.pk_wavescroll .pk_wavedrag{ + display:block; + width:100%; + height:100%; + min-width:50px; + position:absolute; + background:#246e6e; /*#2c7b7b;*/ +} +.pk_wavescroll .pk_wavedrag_l{ + float:left; + width:12px; + height:100%; + cursor: col-resize; +} +.pk_wavescroll .pk_wavedrag_r{ + float:right; + width:12px; + height:100%; + cursor: col-resize; +} + +.pk_play.pk_act{ + background:#da4f4f; + background: linear-gradient(-75deg, #d01111, #ff8d8d); +} + +.pk_loop.pk_act{ + background:gold; + background: linear-gradient(-65deg, #43C6AC, #F8FFAE); +} + +.wavesurfer-region{ + opacity: 0.41; + background-color: rgba(30, 30, 162, 1.0); + background: linear-gradient(-65deg, #43b7c6, #d186d2); +} + +.pk_inact, +.pk_app .pk_inact, +.pk_btn.pk_inact{ + opacity:0.5; + cursor:default; +} + +.icon-silence:before { + content:"S"; + height:1px; + font-family:Helvetica, Arial, serif; + display:inline-block; +} +.icon-clearsel:before { + content: "clear selection"; +} +.icon-files-empty:before { + content: "\e925"; +} +.icon-file-text2:before { + content: "\e926"; +} +.icon-zoom-in:before { + content: "\e987"; +} +.icon-zoom-out:before { + content: "\e988"; +} +.icon-hammer:before { + content: "\e996"; +} +.icon-play3:before { + content: "\ea1c"; +} +.icon-pause2:before { + content: "\ea1d"; +} +.icon-stop2:before { + content: "\ea1e"; +} +.icon-backward2:before { + content: "\ea1f"; +} +.icon-forward3:before { + content: "\ea20"; +} +.icon-first:before { + content: "\ea21"; +} +.icon-last:before { + content: "\ea22"; +} +.icon-previous2:before { + content: "\ea23"; +} +.icon-next2:before { + content: "\ea24"; +} +.icon-loop:before { + content: "\ea2d"; +} +.icon-scissors:before { + content: "\ea5a"; +} +.icon-rec:before { + content: "."; + width: 33%; + background: #922; + height: 33%; + margin-top: -2px; + display: inline-block; + vertical-align: middle; + font-size: 0px; + color: transparent; + border-radius: 30px; +} +.icon-rec.pk_act{ + box-shadow: 0 0 6px #d44; + background:#e13030; + animation: fade_anim .6s steps(6, start) infinite alternate; +} + +.pk_mob .icon-rec.pk_act{ + box-shadow:none; +} + +.icon-rec.pk_act:before{ + background:#111; +} + +/** 1up **/ +.pk_oneup{ + margin:0; + position:fixed; + z-index:15; + transition:all 300ms ease-in-out; + left:50%; + top:49%; + transform: translate(-50%,-50%); + padding:10px; + background:rgba(0,0,0,0.66); + color:#eee; + border:1px solid #333; + border-radius:3px; + font-size:16px; + user-select: none; + pointer-events:none; +} + + +/** modal **/ + +.pk_modal_back{ + z-index:8; + position:absolute; + left:0; + top:0; + + + overflow:auto; + right:0; + + /*display:flex; + justify-content:center; + align-items:center;*/ + + /* + overflow:visible; + min-height:100%; + */ + + display:block; + /*min-width:560px;*/ + + height:100%; + /*min-height:300px;*/ + + background:rgba(0,0,0,0.62); + + touch-action:manipulation; + -webkit-overflow-scrolling:touch +} +.pk_modal_cnt{ + position:absolute; + /* position:relative; */ + + top:0%; + + + /*left:50%; + transform:translate(-50%, 0px);*/ + + min-height:100%; + + /* width:100%; */ + min-width:100%; + + padding:40px 20px; + box-sizing:border-box; + + display:flex; + justify-content:center; + align-items:center +} +.pk_modal{ + position:relative; + margin:-40px auto 0 auto; + border:1px solid #333; + background:#222; + display:block; + box-shadow: 0 0 20px #333; + min-width: 344px; + min-height: 168px; + + animation: pk_shw .2s ease-out 0ms 1; + + margin-top:0; +} + +.pk_modal.pk_bigger{ + min-width: 400px; +} + +.pk_modal_title { + padding: 8px 15px; + text-shadow: 0 0 1px black; + border-bottom: 1px solid #444; + margin-bottom: 10px; + font-size:14px; +} + +.pk_modal_main{ + position:relative; + clear: both; + padding: 0 15px 52px 15px; +} + +.pk_modal_bottom { + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 22px; + border-top: 1px solid #444; + padding: 12px 15px; + /*overflow: hidden;*/ + background:#222; +} + +.pk_modal_a_bottom{ + float: right; + display: block; + padding: 4px 10px; + border: 1px solid #999; + border-radius: 21px; + color:#eee; + font-size: 12px; + margin-left: 16px; + -webkit-user-select:none; + user-select:none; +} +.pk_modal_a_bottom:hover{ + /*background: #eee; + color: #111; + border-color: #eee;*/ + border-color: teal; + box-shadow: 0 0 6px rgba(39, 136, 158, 0.4); +} + +.pk_modal_a_red{ + border-color: red; + color: #000; + background: #b41919; + float: left; + margin-left: 2px; +} + +.pk_modal_cancel{ + border-color: #c87a7a; + color: #c87a7a; + transition: background 120ms; +} + +.pk_modal_cancel:hover{ + box-shadow: 0 0 6px rgba(158, 39, 39, 0.6); + border-color: unset; + background: #280a0ac7; +} + +.pk_modal_a_accpt{ + border-color: #99c2c6; + color: #cbe2e3; + transition: border-color 120ms, color 120ms; +} + +.pk_modal_a_accpt:hover{ + color: #99c2c6; +} + +.pk_modal .pk_txt{ + display: block; + margin-top:6px; + background: #111; + outline: 0; + padding: 4px 8px; + color: #eee; + border-radius: 4px; + border: 1px solid #333; + border-bottom: 1px solid #444; +} + + +.pk_modal_a_top{ + float: right; + font-size: 11px; + color: #99cccc; + display: block; + padding: 2px 4px; +} +.pk_modal_a_top.pk_act{ + text-decoration: underline; + color:#9ad6d6; +} + +/* +.pk_modal_a_top.pk_act:before{ + content: '►'; + text-decoration: none; + position: absolute; + margin: 3px 0 0px -10px; + font-size: 8px; +} +*/ + +.pk_col{ + float:left; + margin-top:8px; + text-align:center; + position:relative; +} + +.pk_h200 .pk_col{ + height:220px; + max-width:60px; + width:10%; + min-width:38px; +} +.pk_dens .pk_h200 .pk_col{ + max-width:54px; + overflow:hidden; +} +.pk_dens .pk_h200 .pk_val{ + padding: 2px 6px; + font-size: 11px; +} +.pk_h200 .pk_col .pk_vert{ + display: inline-block; + width:160px; + -ms-transform-origin: 80px 80px; + transform-origin: 80px 80px; + margin-left:50%; + margin-top:12px; +} + +.pk_h200 .pk_btm{ + bottom:10px; + font-size:12px; +} + +.pk_h200 .pk_val{ + margin:0; + background: #1b1b1b; + padding:2px 8px; +} + +.pk_wave_cursor{ + position:absolute; + left:0; + top:0; + z-index:5; + margin-left: -2px; + bottom:0; + width:1px; + pointer-events:none; + border-right:1px dashed gold; + transform:translate3d(0,0,0); +} + +.pk_row{ + clear: both; + border-bottom: 1px solid #444; + overflow: hidden; + padding-top: 6px; + margin-bottom: 4px; + padding-bottom: 12px; +} +.pk_row:last-child{ + border:none; +} +.pk_row input{ + float: left; +} +.pk_row label{ + display:block; + margin-bottom: 4px; + margin-right:24px; +} +.pk_row label.pk_line{ + display: block; + float: left; + text-align: center; + width: 80px; + padding-right: 6px; + margin: 8px 0; +} +.pk_btm{ + position:absolute; + user-select:none; + left:0;right:0;bottom:0; +} +.pk_val{ + background: #111; + padding: 4px 10px; + text-align: center; + min-width: 30px; + border-radius: 11px; + border-bottom: 1px solid #4e4e4e; + font-size: 12px; + border-top: 1px solid #000; + user-select:none; +} + +.pk_row .pk_val{float: right;margin:4px 0;} + +.pk_sel{float:left;max-width:92px} +.pk_sel_edt{ + width: 24px; + height: 22px; + display: block; + float: left; + font-weight: bold; + border-radius: 6px; + text-align: center; + margin-left: 6px; + color: #888; + cursor:pointer; + position:relative; + visibility: hidden; + opacity: 0; + border: 1px solid #888; + transition: opacity 620ms; +} + +.pk_sel_edt > span{ + display: block; + -ms-user-select: none; + user-select: none; + visibility: hidden; + line-height: 26px; + opacity: 0; + pointer-events: none; + font-family: Arial, sans-serif; + position: absolute; + bottom: -30px; + left: 50%; + transform: translate(-50%, 0); + white-space: nowrap; + background: #000; + font-size: 11px; + font-weight: normal; + padding: 0 6px; + border-radius: 3px; + transition: opacity 320ms 296ms; + color: #eee; + z-index: 6; + letter-spacing: normal; +} + +.pk_sel_edt:hover > span{ + visibility:visible; + opacity: 1; +} + +button{background-color:rgb(221, 221, 221);} +select{ + display: block; + padding: 0 10px; + border: 1px solid #999; + border-radius: 21px; + font-size: 12px; + height:25px; + outline: 0; + background: transparent; + color: #eee; + line-height:24px; + font-weight: lighter; + margin:0; +} + +select option{ + background:#333; + padding:2px 0; + margin:2px 0; +} + +.pk_vert, +.pk_horiz { + -webkit-appearance: none; + -webkit-tap-highlight-color: rgba(255, 255, 255, 0); + width: 100%; + height: 10px; + margin: 10px 0; + border: none; + padding: 1px 2px; + border-radius: 14px; + background: #111; + box-shadow: inset 0 1px 0 0 #0d0e0f, inset 0 -1px 0 0 #3a3d42; + -webkit-box-shadow: inset 0 1px 0 0 #0d0e0f, inset 0 -1px 0 0 #3a3d42; + outline: none; /* no focus outline */ + max-width:235px; +} + +.pk_vert{ + -ms-transform:rotate(270deg) translate(0,-5px); + transform:rotate(270deg) translate(0,-5px); +} + +input.pk_horiz.pk_w180{ + max-width:200px; +} + +.pk_bigger .pk_horiz { + max-width:180px; +} +.pk_vert::-moz-range-track, +.pk_horiz::-moz-range-track { + border: inherit; + background: transparent; +} + +.pk_vert::-ms-track, +.pk_horiz::-ms-track { + border: inherit; + color: transparent; /* don't drawn vertical reference line */ + background: transparent; +} +.pk_vert::-ms-fill-lower, +.pk_vert::-ms-fill-upper, +.pk_horiz::-ms-fill-lower, +.pk_horiz::-ms-fill-upper { + background: transparent; +} +.pk_vert::-ms-tooltip, +.pk_horiz::-ms-tooltip { + display: none; +} + +/* thumb */ +.pk_vert::-webkit-slider-thumb, +.pk_horiz::-webkit-slider-thumb { + -webkit-appearance: none; + width: 38px; + height: 18px; + border: 1px solid black; + border-radius: 12px; + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #47497d), color-stop(100%, #519fa7)); /* android <= 2.2 */ + background-image: -webkit-linear-gradient(top , #47497d 0, #519fa7 100%); /* older mobile safari and android > 2.2 */; + background-image: linear-gradient(to bottom, #47497d 0, #519fa7 100%); +} +.pk_vert::-moz-range-thumb, +.pk_horiz::-moz-range-thumb { + width: 38px; + height: 18px; + border: 1px solid black; + border-radius: 12px; + background-image: linear-gradient(to bottom, #47497d 0, #519fa7 100%); /* W3C */ +} +.pk_vert::-ms-thumb, +.pk_horiz::-ms-thumb { + width: 38px; + height: 18px; + border-radius: 12px; + border: 1px solid black; + background-image: linear-gradient(to bottom, #47497d 0, #519fa7 100%); /* W3C */ +} + + +/* Base for label styling */ +.pk_check:not(:checked), +.pk_check:checked { + position: absolute; + left: -9999px; +} +.pk_check:not(:checked) + label, +.pk_check:checked + label { + position: relative; + padding-left: 30px; + display:inline-block; + height:24px; + line-height:24px; + cursor: pointer; +} + +/* checkbox aspect */ +.pk_check:not(:checked) + label:before, +.pk_check:checked + label:before { + content: ''; + outline:0; + position: absolute; + left: 0; top: 0; + width: 20px; height: 20px; + border: 1px solid #222; + background: #111; + border-radius: 20px; + box-shadow: inset 0 1px 0 0 #000000, inset 0 -1px 0 0 #4d5158; +} +/* checked mark aspect */ +.pk_check:not(:checked) + label:after, +.pk_check:checked + label:after { + content: ' '; + outline:0; + position: absolute; + top: 3px; + left: 3px; + background: #99c2c6; + transition: all .1s; + border-radius: 20px; + height: 16px; + width: 16px; +} + +.pk_check:checked + label:before { + border: 1px solid #666; +} + +/* checked mark aspect changes */ +.pk_check:not(:checked) + label:after { + opacity: 0; + transform: scale(0); +} +.pk_check:checked + label:after { + opacity: 1; + transform: scale(1); +} +/* disabled checkbox */ +.pk_check:disabled:not(:checked) + label:before, +.pk_check:disabled:checked + label:before { + box-shadow: none; + border-color: #bbb; + background-color: #ddd; +} +.pk_check:disabled:checked + label:after { + color: #999; +} +.pk_check:disabled + label { + color: #aaa; +} + + +.pk_grabbing wave, +.pk_grabbing{ + cursor: move !important; + cursor: -webkit-grabbing !important; +} + +.pk_modal_anim{ + animation: pk_ppr .22s ease-out 0ms 1; +} + +@keyframes pk_ppr{ + 0%{transform:scale(.2)} + 100%{transform:scale(1)} +} +@keyframes pk_shw{ + 0%{opacity:0} + 100%{opacity:1} +} + +@keyframes pk_loader_anim { +/* 0% {width: 0%;margin-left:0;} + 25% {width: 50%;;margin-left:0;} + 50% {margin-left: 30%;width:40%;} + 75% {margin-left: 50%;width:60%;} + 100% {margin-left: 100%;width:60%;} +*/ + + 0% {transform:scaleX(0) translate3d(0,0,0);} + 25% {transform:scaleX(0.5) translate3d(0,0,0);} + 50% {transform:scaleX(0.4) translate3d(70%,0,0);} + 75% {transform:scaleX(0.6) translate3d(50%,0,0);} + 100% {transform:scaleX(1) translate3d(100%,0,0);} +} + +@keyframes fade_anim { + to { + opacity:.78 + } +} + + +@media only screen and (max-height: 438px) { + .pk_zoombtn .pk_zoom_out_v, + .pk_zoombtn .pk_zoom_in_v{ + display:none !important; + } +} + +@media only screen and (max-width: 1250px) { + .pk_ctns, + .pk_transport{ + float: none; + display: block; + border: 0; + min-width:auto; + margin-right: 14px; + margin-top: 0; + height: 28px; + } + .pk_selection{ + min-width:auto; + } + .pk_tb .pk_btn { + font-size: 12px; + width: 24px; + height: 23px; + margin: 0px 3px; + line-height: 24px; + } + .pk_sellist .pk_title{ + font-size:10px; + } + .pk_selection .pk_sellist { + width: 296px; + } + + .pk_tb .pk_selection .pk_btn{ + width: 60px; + line-height: 10px; + font-size: 11px; + height: 32px; + margin-top: 3px; + margin-left: 10px; + } + + .pk_mark1{ + width:5.554%; + } + .pk_mark1.pk_odd{ + display:none; + } +} + +@media only screen and (max-width: 864px) { + .pk_selection .pk_sellist div{ + margin:0 16px 0 0; + } + .pk_sellist .pk_title{ + display:none; + } + .pk_tb .pk_selection .pk_btn{ + width:34px; + } + .pk_selection .pk_sellist { + width: 212px; + } + .icon-clearsel:before { + content: "clear"; + } + .pk_mark1{ + font-size:9px; + letter-spacing:0; + } +} + +@media only screen and (max-width: 779px) { + .pk_selection { + display:none !important; + } + + .pk_btn button{ + padding: 2px 12px; + } + + .pk_timecontainer{ + margin-right:10px; + width:200px + } + .pk_timing{ + font-size:24px; + padding:10px 0 0 8px + } + .pk_total_dur, .pk_hover_dur{ + font-size:13px + } + .pk_hdr .pk_btn{ + margin:2px 10px 0 10px + } + .pk_tbc{ + overflow-x:scroll; + background:#363636; + border-bottom: 1px solid #000; + -webkit-overflow-scrolling:touch; + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE 10+ */ + } + .pk_tbc::-webkit-scrollbar { /* WebKit */ + width: 0; + height: 0; + } + + .pk_tb{ + padding:6px 0px 6px 14px; + white-space:nowrap; + border-bottom:none; + } + .pk_mob .pk_ctns, .pk_mob .pk_transport { + height:36px; + } + .pk_mark1{font-size:8px} + + .pk_tmpMsg{ + font-size:14px; + line-height:28px; + margin-left:-120px; + width:240px + } + + .pk_mob .pk_hdr{ + padding: 20px 5px 0 5px; + } + + .pk_mob .pk_transport, + .pk_mob .pk_ctns, + .pk_mob .pk_btngroup { + float:none; + display:inline-block; + } + .pk_mob .pk_btngroup{ + padding-top:8px; + } + .pk_mob .pk_tb .pk_btn { + font-size: 16px; + width: 32px; + height: 32px; + margin: 0px 4px; + line-height: 24px; + } + + .pk_h200 .pk_col { + width: 20%; + overflow: hidden; + } + + .pk_zoombtn button{ + height:19px; + } + + .pk_wavescroll{ + margin-bottom:8px; + height:16px; + } + + .pk_markers{ + margin-top:3px; + } + + .pk_lcldrf .pk_lcla{ + margin-left:14px; + font-size:12px; + } +} + +@media only screen and (max-width: 400px) { + .pk_hdr .pk_btn{ + margin:2px 4px 0 4px + } +} + + +.pk_av canvas{ + opacity:0; + transition: opacity 440ms; +} + +.pk_dck{ + position:relative; + display:none; +} + +.pk_frqan{ + border:1px solid #444; + width:380px; + margin:15px 15px 12px 15px; + height:110px; + border-radius: 3px; + position:absolute; + z-index:7; + background:#111 +} + +.pk_wavepoint{ + position: absolute; + width: 2px; + background: #d7ba6d; + height: 100%; + pointer-events:none; + top: 0; + transform:translate3d(0,0,0); + display: none; +} + +.pk_peq{ + width:450px; + height:225px; + z-index:3; + position:relative; +} + +.pk_peq2{ + position:absolute; + left: 14px; + width:225px; + height:112px; + z-index:2; + transform:scale(2); + transform-origin:0 0; +} + +.pk_peq3{ + font-size:10px; + color:#666; + position:relative; + z-index:1; +} + +.pk_peq3 span span{ + position: absolute; + top: -229px; + width: 1px; + display: block; + height: 225px; + border-left: 1px dashed #585858; + left: 50%; +} + +.pk_peq4{ + font-size:9px; + color:#666; + position:absolute; + left: 0; + top: 0; + height: 225px; +} + +.pk_peq4:before{ + content: ' '; + position: absolute; + background: #1b1a1a; + width: 450px; + height: 225px; + display: block; + left: 15px; + top: 5px; +} + +.pk_peq4 span span{ + position: absolute; + width: 446px; + left: 18px; + display: block; + top: 5px; + height: 1px; + border-top: 1px solid #4d4729; +} + +.pk_peq4 span{ + text-align:center; + top: 50%; + left: 0px; + width: 15px; + position: absolute; +} + +.pk_pgeq_els{ + margin-bottom: 0px; + padding: 6px 0; + border-bottom: 1px solid #333; + + transition:background 120ms; +} + +.pk_pgeq_els:hover{ + background:#3b413f; +} + +.pk_pgeq_els.pk_act{ + background:#24302c; +} + +.pk_pgeq_els > span{ + display:inline-block; + width:18%; + text-align:center; + color: #ccc; + font-size: 12px; +} + +.pk_pgeq_els .pk_txlft{ + text-align: left; + width:20%; +} + +.pk_pgeq_els .pk_del{ + width:8%; + overflow:hidden; + font-size:8px; + text-align:left; +} + +.pk_pgeq_els > div{ + position:relative; + display:inline-block; + width:18%; + text-align: center; +} + +.pk_pgeq_els .pk_val{ + float:none; + margin:0; + color:#fff; + outline:0; + min-width: 32px; + max-width: 44px; + border-left: none; + border-right: none; +} + +.pk_pgeq_els select{ + margin: 0 auto; + padding:0 0 0 10px; +} + +.pk_pgeq_freq{ + position: absolute; + background: #212121; + padding: 2px 20px; + z-index: 9; + width: 220px; + border-radius: 20px; + left: -100px; + border: 1px solid #313131; + top: 30px; + box-shadow: 0 1px 13px 4px #090909; +} + +.pk_pgeq_freq .pk_arr{ + pointer-events:none; + width: 0px; + height: 0px; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + position: absolute; + border-bottom: 8px solid #2f2f2f; + left: 50%; + top: -8px; +} + + +.pk_pgeq_els .pk_check:not(:checked) + label, +.pk_pgeq_els .pk_check:checked + label { + position: relative; + padding-left: 25px; + display: inline-block; + height: 24px; + line-height: 20px; + cursor: pointer; + font-size: 10px; + margin:0; +} + +.pk_pgeq_els i{ + display: inline-block; + padding: 0 8px; + margin-right: 8px; +} + +label.pk_dis, +.pk_pgeq_els.pk_dis .pk_gain{ + pointer-events: none; + opacity:0.5; +} + +.pk_pglst{ + max-height: 160px; + overflow-y: scroll; + padding-bottom: 20px; + overflow: -moz-scrollbars-none; + -ms-overflow-style: none; +} + + +.pk_pglst::-webkit-scrollbar { + width: 0px; +} + +input[type=number]::-webkit-inner-spin-button, +input[type=number]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; +} + +body.pk_stndln{ + padding-bottom:600px; + overflow:hidden; +} + +.pk_stndln .pk_fxd{ + height:100%; + position:fixed; + left:0;top:0;width:100%; +} +.pk_stndln .pk_modal_back { + position:fixed; +} + +.pk_fnt10 .pk_modal_a_bottom{ + font-size:10px +} + +.pk_tbs{ + margin-left: -14px; + margin-right: -14px; + margin-top: -10px; + text-align: center; +} + +.pk_tbsa{ + width: 33.3%; + display: inline-block; + padding: 10px 0; + box-sizing: border-box; + border-right: 1px solid #111; + border-bottom: 1px solid #111; + background:#303030; +} + +.pk_tbsa:hover{ + box-shadow: inset 0 -2px 6px #181818; +} + +.pk_tbsa.pk_act{ + box-shadow:none; + border-bottom:none; + background:transparent; + text-shadow:0 0 1px #000 +} + +#pk_tmp_tap{ + width: 100%; + background: #151515; + min-width: 500px; + height: 30px; + position:relative; + overflow:hidden; + clear: both; + border-bottom: 1px solid #333; + border-left: 1px solid #333; + border-right: 1px solid #333; + margin-bottom: 10px; + box-sizing: border-box; +} + +#pk_tmp_tap2 .pk_obj, +#pk_tmp_tap .pk_obj{ + width: 100%; + height: 100%; + z-index:2; + background: linear-gradient(to right, rgba(68, 18, 19, 0.75) 0%,rgba(255,255,255,0) 20%,rgba(255,255,255,0) 100%); + border-left: 2px solid #f52b2b; + position: absolute; + top: 0; + transform: translate3d(100%,0,0); + left: -4px; + will-change: transform; + overflow:hidden; + transition: transform 3.3s linear; +} + +#pk_tmp_tap2 .pk_obj{ + transform: translate3d(50%,0,0); + transition:transform 1770ms linear; +} + +#pk_tmp_tap .pk_obj2{ + width:100px; + display:block; + position:absolute; + left:50%; + line-height:30px; + margin-left:-50px; + text-align:center; + opacity:.6; + font-size:16px; + transition:opacity 200ms; +} + +#pk_tmp_tap3{ + width: 100%; + background: #333; + min-width: 500px; + min-height: 200px; + border: 1px solid #424242; + overflow:hidden; + position:relative; + box-sizing: border-box; + margin-top:10px; + transition: background 70ms; +} + +#pk_tmp_tap3:hover{ + background:#363636; +} + +#pk_tmp_tap3.pk_act{ + background:#555; +} + +.pk_modal_a_bottom.pk_act{ + color:#000; + background:#ccc; +} + +.pk_modal_a_bottom.pk_inact{ + pointer-events:none; +} + +.pk_id3ttl{ + font-weight: bold; + padding: 2px 10px; + display: inline-block; + min-width: 64px; +} +.pk_lcldrf{ + padding: 6px 0 14px 0; + margin-top: 10px; + overflow: hidden; + position:relative; + border-bottom: 1px solid #444; + + margin-left:-5px; + padding-left:5px; + margin-right:-5px; + padding-right:5px; +} + +.pk_lcldrf:hover{ + background:#292929; +} + +.pk_lcldrf .pk_i{ + color:#909090; + font-size:11px; + padding-right:5px; + line-height:16px; + vertical-align:middle; + min-width:20px; + display:inline-block; +} + +.pk_lcla{ + margin:0 10px; + margin-left:15px; + vertical-align: middle; +} +.pk_lcla2{ + position: absolute; + left: 7px; + bottom: 16px; + background: rgba(0,0,0,0.75); + border-radius: 4px; + font-size: 9px; + display: block; + padding: 1px 8px; + border: 1px solid rgba(255,255,255,0.3); +} +.pk_lcla2.pk_act{ + background:rgba(255,255,255,0.74); + color:#111; +} + +.pk_lcli{ + max-width:120px; + width:120px; + vertical-align:middle; + height:48px; + background:#111; +} + +.pk_lcls{ + min-width: 74px; + width:25%; + margin-bottom: 6px; + display: inline-block; + vertical-align:top; + line-height:16px; + white-space:nowrap; +} + +.pk_aut_act, +.pk_aut{ + box-shadow: 0px 0px 20px #eee, inset 0px 0px 4px gold; +} diff --git a/audiomass-editor/src/manifest.json b/audiomass-editor/src/manifest.json new file mode 100644 index 0000000..2fe4d69 --- /dev/null +++ b/audiomass-editor/src/manifest.json @@ -0,0 +1,14 @@ +{ + "name": "Audiomass - Audio Editor", + "short_name": "Audiomass - Audio Editor", + "start_url": ".", + "scope": ".", + "display": "standalone", + "icons": [ + { + "src": "icon.png", + "type": "image/png", + "sizes": "144x144" + } + ] +} \ No newline at end of file diff --git a/audiomass-editor/src/modal.js b/audiomass-editor/src/modal.js new file mode 100755 index 0000000..856616c --- /dev/null +++ b/audiomass-editor/src/modal.js @@ -0,0 +1,421 @@ +(function ( w, d ) { + + var _id = 0; + + function PKSimpleModal ( config ) { + var q = this; + + this.id = config.id ? config.id : (++_id); + + var el = d.createElement ('div'); + this.els = { + toolbar:[], + bottom:[] + }; + el.className = 'pk_modal ' + (config.clss ? config.clss : ''); + + q.el = el; + + // backdrop + var el_back = d.createElement ('div'); + el_back.className = 'pk_modal_back'; + this.el_back = el_back; + + // var centerer + var el_cont = d.createElement ('div'); + el_cont.className = 'pk_modal_cnt'; + this.el_cont = el_cont; + + // title + var el_title = d.createElement ('div'); + el_title.className = 'pk_noselect pk_modal_title'; + el_title.innerHTML = ''+ (config.title || '') +''; + el.appendChild ( el_title ); + this.el_title = el_title; + + // main + var el_main = d.createElement ('div'); + el_main.className = 'pk_modal_main'; + el.appendChild ( el_main ); + this.el_body = el_main; + + // bottom buttons + var el_bottom = d.createElement ('div'); + el_bottom.className = 'pk_noselect pk_modal_bottom'; + // ----------- + var a_cancel = d.createElement ('a'); + a_cancel.innerHTML = 'CANCEL'; + a_cancel.className = 'pk_modal_cancel pk_modal_a_bottom'; + a_cancel.onclick = function () { + q.Destroy (); + }; + el_bottom.appendChild ( a_cancel ); + + // check if we need to construct more buttons from the config... + if (config.buttons && config.buttons.length > 0) + { + for (var i = 0; i < config.buttons.length; ++i) + { + var curr = config.buttons[i]; + + if (!curr.title || !curr.callback) continue; + var a_bottom = d.createElement ('a'); + a_bottom.innerHTML = curr.title; + a_bottom.className = 'pk_modal_a_bottom ' + (curr.clss ? curr.clss : ''); + + if (curr.callback) + { + (function ( callback ) { + a_bottom.onclick = function () { + callback ( q ); + }; + })( curr.callback ); + } + q.els.bottom.push (a_bottom); + el_bottom.appendChild ( a_bottom ); + } + } + el.appendChild ( el_bottom ); + + // ----- + if (config.toolbar && config.toolbar.length > 0) + { + for (var i = 0; i < config.toolbar.length; ++i) + { + var curr = config.toolbar[i]; + if (!curr.title || !curr.callback) continue; + var a_link = d.createElement ('a'); + a_link.innerHTML = curr.title; + a_link.className = 'pk_modal_a_top ' + (curr.clss ? curr.clss : ''); + el_title.appendChild ( a_link ); + + if (curr.callback) + { + (function ( callback ) { + a_link.onclick = function () { + callback ( q, this ); + }; + })( curr.callback ); + } + q.els.toolbar.push (a_link); + } + } + + this.ondestroy = config.ondestroy; + if (config.body) q.el_body.innerHTML = config.body; + if (config.onpreset) this.onpreset = config.onpreset; + if (config.setup) config.setup ( this ); + }; + + PKSimpleModal.prototype.Show = function () { + + this.el_back.appendChild ( this.el_cont ); + this.el_cont.appendChild ( this.el ); + + d.body.appendChild ( this.el_back ); + + return (this); + }; + + PKSimpleModal.prototype.Destroy = function () { + + if (this.ondestroy) { + this.ondestroy ( this ); + this.ondestroy = null; + } + this.els = null; + d.body.removeChild ( this.el_back ); + }; + + + // Extended modal + function PKAudioFXModal ( config, app ) { + var toolbar = null; + + if (config.preview) + { + toolbar = [ + { + title:'ON', + clss:'pk_inact', + callback: function ( q, el ) { + app.fireEvent ('RequestActionFX_TOGGLE'); + } + }, + { + title:'Preview', + callback: function ( q ) { + config.preview && config.preview ( q ); + } + } + ]; + } + + var inner_modal = new PKSimpleModal({ + id: config.id, + title: config.title, + clss: config.clss, + presets: config.presets, + updateFilter: config.updateFilter, + ondestroy: function ( q ) { + + app.fireEvent ('DidCloseFX_UI'); + + app.stopListeningFor ('DidStartPreview', q._evstart); + app.stopListeningFor ('DidStopPreview', q._evstop); + app.stopListeningFor ('DidTogglePreview', q._evtoggle); + app.stopListeningFor ('DidSetPresets', q._updatePresets); + app.stopListeningFor ('RequestActionFX_UPDATE_PREVIEW', q._updpreview); + app.stopListeningFor ('RequestSetPresetActive', q._updpreset); + + app.fireEvent ('RequestActionFX_PREVIEW_STOP'); + + // if preview remove callback + app.ui.KeyHandler.removeCallback ('ksp' + q.id); + + + config.ondestroy && config.ondestroy ( q ); + }, + toolbar: toolbar, + buttons: config.buttons, + body: config.body, + onpreset: config.onpreset, + setup:function( q ) { + app.fireEvent ('RequestActionFX_TOGGLE', 1); + + var slf = this; + app.ui.KeyHandler.addCallback ('ksp' + q.id, function ( key, map ) { + if (!app.ui.InteractionHandler.check ('modalfx')) return ; + + var tb = slf.toolbar; + if (tb && tb.length > 0) + { + var k = tb.length; + while (k-- > 0) { + if (tb[k].title === 'Preview') { + tb[k].callback ( q ); + break; + } + } + } + }, [32]); + + q._evstart = function () { + q.els.toolbar[0].classList.remove ('pk_inact'); + q.els.toolbar[1].classList.add ('pk_act'); + }; + q._evstop = function () { + q.els.toolbar[0].classList.add ('pk_inact'); + q.els.toolbar[1].classList.remove ('pk_act'); + } + + q._evtoggle = function ( val ) { + var el = q.els.toolbar[0]; + if (val) el.innerHTML = 'ON'; + else el.innerHTML = 'OFF'; + }; + + var stopped_listening = false; + q._updpreview = function ( val ) { + var sel_opt = q.el_presets.options[q.el_presets.selectedIndex]; + var btn = q.el.getElementsByClassName('pk_sel_edt')[0]; + + if (val === 't') + { + if (sel_opt && sel_opt.getAttribute('data-custom')) { + btn.style.visibility = 'visible'; + btn.style.opacity = '1'; + app.stopListeningFor ('RequestActionFX_UPDATE_PREVIEW', q._updpreview); + } + else + { + btn.style.visibility = 'hidden'; + btn.style.opacity = '0'; + + app.stopListeningFor ('RequestActionFX_UPDATE_PREVIEW', q._updpreview); + + //if (stopped_listening) + //{ + setTimeout(function (){ + app.listenFor ('RequestActionFX_UPDATE_PREVIEW', q._updpreview); + }, 100); + stopped_listening = false; + //} + } + return ; + } + + // if (sel_opt && sel_opt.getAttribute('data-custom')) { + btn.style.visibility = 'visible'; + btn.style.opacity = '1'; + stopped_listening = true; + app.stopListeningFor ('RequestActionFX_UPDATE_PREVIEW', q._updpreview); + // } + }; + + q._updpreset = function ( fx_id, preset_id ) { + if (fx_id && fx_id !== q.id) { + return ; + } + + var opts = q.el_presets.getElementsByTagName('option'); + var ll = opts.length; + var curr = null; + + while (ll-- > 0) { + curr = opts[ll]; + + if (curr.getAttribute('data-custom') === preset_id) { + curr.selected = 'selected'; + break; + } + } + }; + + q._updatePresets = function ( fx_id, presets ) { + if (fx_id && fx_id !== q.id) { + return ; + } + + var d = document; + var sel_presets = q.el.getElementsByClassName ('pk_sel'); + + // if presets exist remove them + if (sel_presets.length > 0) + { + sel_presets = sel_presets[0]; + var opts = sel_presets.getElementsByTagName('option'); + var ll = opts.length; + var curr = null; + + while (ll-- > 0) { + curr = opts[ll]; + + if (curr.getAttribute('data-custom')) { + sel_presets.removeChild( curr ); + } + } + + if (presets.length === 0) return ; + + var opt = d.createElement ('option'); + // opt.value = '---custom----'; + opt.setAttribute ('disabled', '1'); + opt.setAttribute ('data-custom', '1'); + opt.innerHTML = '----custom-----'; + sel_presets.appendChild( opt ); + + for (var i = 0; i < presets.length; ++i) + { + var opt = d.createElement ('option'); + var curr = presets[ i ]; + opt.value = curr.val; + opt.setAttribute ('data-custom', curr.id); + opt.innerHTML = curr.name; + sel_presets.appendChild( opt ); + } + + return ; + } + else + { + sel_presets = d.createElement ('select'); + sel_presets.className = 'pk_sel'; + } + + if (presets.length === 0) return ; + + + for (var i = -1; i < presets.length; ++i) + { + var opt = d.createElement ('option'); + + if (i === -1) + { + opt.value = 'null'; + opt.innerHTML = 'Presets'; + } + else + { + var curr = presets[ i ]; + opt.value = curr.val; + opt.innerHTML = curr.name; + } + sel_presets.appendChild( opt ); + } + + sel_presets.onchange = function () { + var val_arr = this.value.split(','); + var els = q.el.getElementsByTagName('input'); + + q._updpreview ('t'); + + if (q.onpreset) + { + q.onpreset (this.value); + return ; + } + + var len = els.length; + + for (var i = 0; i < len; ++i) { + if (!val_arr[ i ]) break; + + var curr_val = val_arr[ i ].trim (); + var curr_input = els[ i ]; + + if (curr_val === 'null') continue; + + if (curr_input.type === 'checkbox' || curr_input.type === 'radio') + curr_input.checked = curr_val; + else + { + curr_input.value = curr_val; + curr_input.oninput && curr_input.oninput.apply (curr_input); + } + } + }; + var btm = q.el.getElementsByClassName('pk_modal_bottom')[0]; + + btm.appendChild ( sel_presets ); + q.el_presets = sel_presets; + + // now add preset edit button + var edit_presets = d.createElement ('a'); + edit_presets.className = 'pk_sel_edt'; + edit_presets.innerHTML = '...Save or Modify preset'; + edit_presets.onclick = function () { + app.fireEvent ('RequestSavePreset'); + }; + + btm.appendChild ( edit_presets ); + app.listenFor ('RequestActionFX_UPDATE_PREVIEW', q._updpreview); + app.listenFor ('RequestSetPresetActive', q._updpreset); + }; + + + app.listenFor ('DidStartPreview', q._evstart); + app.listenFor ('DidStopPreview', q._evstop); + app.listenFor ('DidTogglePreview', q._evtoggle); + app.fireEvent ('DidOpenFX_UI', q); + + if (config.updateFilter) q.updateFilter = config.updateFilter; + + if (config.presets) + { + q._updatePresets (null, config.presets); + if (config.custom_pres) q._updatePresets (null, config.custom_pres); + + app.listenFor ('DidSetPresets', q._updatePresets); + } + + config.setup && config.setup ( q ); + } + }); + + return (inner_modal); + }; + + w.PKSimpleModal = PKSimpleModal; + w.PKAudioFXModal = PKAudioFXModal; +})( window, document ); \ No newline at end of file diff --git a/audiomass-editor/src/oneup.js b/audiomass-editor/src/oneup.js new file mode 100755 index 0000000..a9beb8d --- /dev/null +++ b/audiomass-editor/src/oneup.js @@ -0,0 +1,29 @@ +(function ( w, d ) { + + function OneUp ( _text, _time, _clss ) { + var el = d.createElement ('div'); + var cl = 'pk_oneup pk_noselect'; + + el.style.cssText = 'margin-top:20px;opacity:0'; + if (_clss) cl = cl + ' ' + _clss; + + el.className = cl; + el.innerHTML = _text || ''; + + d.body.appendChild ( el ); + setTimeout (function() { + el.style.cssText = 'margin-top:0px;opacity:1'; + + setTimeout (function() { + el.style.cssText = 'margin-top:-20px;opacity:0'; + + setTimeout (function() { + el.parentNode.removeChild ( el ); + el = null; + }, 330); + }, _time || 720); + }, 25); + } + + w.OneUp = OneUp; +})( window, document ); \ No newline at end of file diff --git a/audiomass-editor/src/phone-switch.jpg b/audiomass-editor/src/phone-switch.jpg new file mode 100755 index 0000000..3620cf1 Binary files /dev/null and b/audiomass-editor/src/phone-switch.jpg differ diff --git a/audiomass-editor/src/recorder.js b/audiomass-editor/src/recorder.js new file mode 100755 index 0000000..55cf665 --- /dev/null +++ b/audiomass-editor/src/recorder.js @@ -0,0 +1,223 @@ +(function ( w, d, PKAE ) { + 'use strict'; + + var PKREC = function ( app ) { + var q = this; + + var media_stream_source = null; + var audio_stream = null; + var audio_context = null; + var script_processor = null; + + var buffer_size = 2048 * 2; // * 2 ? + var channel_num = 1; + var channel_num_out = 1; + + var is_active = false; + + var starting_offset = 0; + var ending_offset = 0; + + var sample_rate = 0; + + var temp_buffers = []; + var temp_buffer_index = -1; + var jumps = 1; + + var end_record_func = null; + var start_record_func = null; + + // temp vars + var curr_offset = 0; + var first_skip = 8; // skip first samples to evade the button's click + var fetchBufferFunction = function( ev ) { + + if (first_skip > 0) { + --first_skip; + return ; + } + + curr_offset += ev.inputBuffer.duration * sample_rate; + if (ending_offset <= curr_offset) + { + ending_offset > 0 && q.stop (); + return ; + } + + var float_array = ev.inputBuffer.getChannelData (0).slice (0); + temp_buffers[ ++temp_buffer_index ] = float_array; + + if (--jumps === 0) + { + requestAnimationFrame(function(){ + jumps = 4; + app.engine.wavesurfer.DrawTemp ( starting_offset, temp_buffers ); + }); + } + }; + + this.isActive = function () { + return (is_active); + }; + + this.setEndingOffset = function ( ending_offset_seconds ) { + ending_offset = ending_offset_seconds; // #### * 100 + }; + + this.start = function ( _at_offset, _end_callback, _start_callback, _sample_rate ) { + if (is_active) return (false); + if (!navigator.mediaDevices) + { + app.fireEvent ('ErrorRec'); + app.fireEvent ('ShowError', 'No recording device found'); + return (false); + } + + starting_offset = _at_offset / 1; + if (isNaN (starting_offset) || !starting_offset) starting_offset = 0; + curr_offset = starting_offset; + + audio_context = app.engine.wavesurfer.backend.getAudioContext (); + if (!audio_context) + { + app.fireEvent ('ErrorRec'); + app.fireEvent ('ShowError', 'No recording device found'); + return (false); + } + + if (audio_context.currentTime === 0) { + app.engine.wavesurfer.backend.source.start (0); + app.engine.wavesurfer.backend.source.stop (0); + } + + if (!_sample_rate) + { + if (app.engine.wavesurfer.backend.buffer) { + sample_rate = app.engine.wavesurfer.backend.buffer.sampleRate; + } + else { + sample_rate = audio_context.sampleRate; + } + } + + end_record_func = function (offset, buffers, _callback) { + async function downsampleAudioBuffer(buffers, sourceSampleRate, targetSampleRate) { + // Step 1: Concatenate the Float32Array chunks + const totalLength = buffers.reduce((sum, buf) => sum + buf.length, 0); + const concatenated = new Float32Array(totalLength); + let offset = 0; + for (let i = 0; i < buffers.length; i++) { + concatenated.set(buffers[i], offset); + offset += buffers[i].length; + } + + // Step 2: Create an AudioBuffer from the concatenated data at the source sample rate + // Create a temporary AudioContext to build the AudioBuffer + const tempCtx = new AudioContext({ sampleRate: sourceSampleRate }); + const audioBuffer = tempCtx.createBuffer(1, totalLength, sourceSampleRate); + audioBuffer.copyToChannel(concatenated, 0, 0); + + // Release the temporary context if you don't need it anymore + tempCtx.close(); + + // Step 3: Use an OfflineAudioContext to resample the AudioBuffer to the target sample rate + const duration = audioBuffer.duration; + const newLength = Math.ceil(duration * targetSampleRate); + const offlineCtx = new OfflineAudioContext(1, newLength, targetSampleRate); + + const source = offlineCtx.createBufferSource(); + source.buffer = audioBuffer; + source.connect(offlineCtx.destination); + source.start(0); + + // Render the resampled AudioBuffer + const renderedBuffer = await offlineCtx.startRendering(); + + // Return the downsampled Float32Array + return renderedBuffer.getChannelData(0); + } + + var source_sample_rate = audio_context ? audio_context.sampleRate : 48000; + if (source_sample_rate === sample_rate) { + _callback (); + _end_callback (offset, buffers); + return ; + } + + downsampleAudioBuffer(buffers, source_sample_rate, sample_rate).then(newBuffer => { + _callback (); + _end_callback (offset, [newBuffer]); + }).catch(error => { + _callback (); + console.error("Error during downsampling:", error); + }); + + // _end_callback (offset, buffers); + }; + start_record_func = _start_callback; + + navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(function( stream ) { + audio_stream = stream; + media_stream_source = audio_context.createMediaStreamSource ( stream ); + + script_processor = audio_context.createScriptProcessor ( + buffer_size, channel_num, channel_num_out + ); + + media_stream_source.connect ( script_processor ); + script_processor.connect ( audio_context.destination ); + + is_active = true; + start_record_func && start_record_func (); + + script_processor.onaudioprocess = fetchBufferFunction; + }).catch(function(error) { + app.fireEvent ('ErrorRec'); + + if (error && error.message) + { + app.fireEvent ('ShowError', error.message); + } + }); + + return (true); + }; + + this.stop = function ( cancel_recording ) { + if (!is_active) return ; + + // fire one last callback to clean temp_buffers? + audio_stream.getTracks().forEach(function (stream) { + stream.stop (); + }); + + script_processor.onaudioprocess = null; + media_stream_source.disconnect (); + script_processor.disconnect (); + + app.engine.wavesurfer.DrawTemp ( null ); + + if (temp_buffers.length > 0 && !cancel_recording) + end_record_func && end_record_func ( starting_offset / sample_rate, temp_buffers, function (){ + is_active = false; + }); + else + end_record_func && end_record_func ( null, null, function(){ + is_active = false; + }); + + sample_rate = 0; + first_skip = 8; + jumps = 1; + temp_buffer_index = -1; + starting_offset = ending_offset = 0; + temp_buffers = []; + audio_stream = null; audio_context = null; + end_record_func = start_record_func = null; + }; + // --- + }; + + PKAE._deps.rec = PKREC; + +})( window, document, PKAudioEditor ); \ No newline at end of file diff --git a/audiomass-editor/src/rnn_denoise.js b/audiomass-editor/src/rnn_denoise.js new file mode 100644 index 0000000..21c080a --- /dev/null +++ b/audiomass-editor/src/rnn_denoise.js @@ -0,0 +1,2747 @@ +// The Module object: Our interface to the outside world. We import +// and export values on it. There are various ways Module can be used: +// 1. Not defined. We create it here +// 2. A function parameter, function(Module) { ..generated code.. } +// 3. pre-run appended it, var Module = {}; ..generated code.. +// 4. External script tag defines var Module. +// We need to check if Module already exists (e.g. case 3 above). +// Substitution will be replaced with actual code on later stage of the build, +// this way Closure Compiler will not mangle it (e.g. case 4. above). +// Note that if you want to run closure, and also to use Module +// after the generated code, you will need to define var Module = {}; +// before the code. Then that object will be used in the code, and you + + +// can continue to use Module afterwards as well. +var Module = typeof Module !== 'undefined' ? Module : {}; + + + +// --pre-jses are emitted after the Module integration code, so that they can +// refer to Module (if they choose; they can also define Module) +// {{PRE_JSES}} + +// Sometimes an existing Module object exists with properties +// meant to overwrite the default module functionality. Here +// we collect those properties and reapply _after_ we configure +// the current environment's defaults to avoid having to be so +// defensive during initialization. +var moduleOverrides = {}; +var key; +for (key in Module) { + if (Module.hasOwnProperty(key)) { + moduleOverrides[key] = Module[key]; + } +} + +var arguments_ = []; +var thisProgram = './this.program'; +var quit_ = function(status, toThrow) { + throw toThrow; +}; + +// Determine the runtime environment we are in. You can customize this by +// setting the ENVIRONMENT setting at compile time (see settings.js). + +var ENVIRONMENT_IS_WEB = false; +var ENVIRONMENT_IS_WORKER = false; +var ENVIRONMENT_IS_NODE = false; +var ENVIRONMENT_IS_SHELL = false; +ENVIRONMENT_IS_WEB = typeof window === 'object'; +ENVIRONMENT_IS_WORKER = typeof importScripts === 'function'; +// N.b. Electron.js environment is simultaneously a NODE-environment, but +// also a web environment. +ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string'; +ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; + + + + +// `/` should be present at the end if `scriptDirectory` is not empty +var scriptDirectory = ''; +function locateFile(path) { + if (Module['locateFile']) { + return Module['locateFile'](path, scriptDirectory); + } + return scriptDirectory + path; +} + +// Hooks that are implemented differently in different runtime environments. +var read_, + readAsync, + readBinary, + setWindowTitle; + +var nodeFS; +var nodePath; + +if (ENVIRONMENT_IS_NODE) { + if (ENVIRONMENT_IS_WORKER) { + scriptDirectory = require('path').dirname(scriptDirectory) + '/'; + } else { + scriptDirectory = __dirname + '/'; + } + + + + + read_ = function shell_read(filename, binary) { + if (!nodeFS) nodeFS = require('fs'); + if (!nodePath) nodePath = require('path'); + filename = nodePath['normalize'](filename); + return nodeFS['readFileSync'](filename, binary ? null : 'utf8'); + }; + + readBinary = function readBinary(filename) { + var ret = read_(filename, true); + if (!ret.buffer) { + ret = new Uint8Array(ret); + } + assert(ret.buffer); + return ret; + }; + + + + + if (process['argv'].length > 1) { + thisProgram = process['argv'][1].replace(/\\/g, '/'); + } + + arguments_ = process['argv'].slice(2); + + if (typeof module !== 'undefined') { + module['exports'] = Module; + } + + process['on']('uncaughtException', function(ex) { + // suppress ExitStatus exceptions from showing an error + if (!(ex instanceof ExitStatus)) { + throw ex; + } + }); + + process['on']('unhandledRejection', abort); + + quit_ = function(status) { + process['exit'](status); + }; + + Module['inspect'] = function () { return '[Emscripten Module object]'; }; + + + +} else +if (ENVIRONMENT_IS_SHELL) { + + + if (typeof read != 'undefined') { + read_ = function shell_read(f) { + return read(f); + }; + } + + readBinary = function readBinary(f) { + var data; + if (typeof readbuffer === 'function') { + return new Uint8Array(readbuffer(f)); + } + data = read(f, 'binary'); + assert(typeof data === 'object'); + return data; + }; + + if (typeof scriptArgs != 'undefined') { + arguments_ = scriptArgs; + } else if (typeof arguments != 'undefined') { + arguments_ = arguments; + } + + if (typeof quit === 'function') { + quit_ = function(status) { + quit(status); + }; + } + + if (typeof print !== 'undefined') { + // Prefer to use print/printErr where they exist, as they usually work better. + if (typeof console === 'undefined') console = /** @type{!Console} */({}); + console.log = /** @type{!function(this:Console, ...*): undefined} */ (print); + console.warn = console.error = /** @type{!function(this:Console, ...*): undefined} */ (typeof printErr !== 'undefined' ? printErr : print); + } + + +} else + +// Note that this includes Node.js workers when relevant (pthreads is enabled). +// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and +// ENVIRONMENT_IS_NODE. +if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { + if (ENVIRONMENT_IS_WORKER) { // Check worker, not web, since window could be polyfilled + scriptDirectory = self.location.href; + } else if (document.currentScript) { // web + scriptDirectory = document.currentScript.src; + } + // blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them. + // otherwise, slice off the final part of the url to find the script directory. + // if scriptDirectory does not contain a slash, lastIndexOf will return -1, + // and scriptDirectory will correctly be replaced with an empty string. + if (scriptDirectory.indexOf('blob:') !== 0) { + scriptDirectory = scriptDirectory.substr(0, scriptDirectory.lastIndexOf('/')+1); + } else { + scriptDirectory = ''; + } + + + // Differentiate the Web Worker from the Node Worker case, as reading must + // be done differently. + { + + + + + read_ = function shell_read(url) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); + xhr.send(null); + return xhr.responseText; + }; + + if (ENVIRONMENT_IS_WORKER) { + readBinary = function readBinary(url) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); + xhr.responseType = 'arraybuffer'; + xhr.send(null); + return new Uint8Array(/** @type{!ArrayBuffer} */(xhr.response)); + }; + } + + readAsync = function readAsync(url, onload, onerror) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.responseType = 'arraybuffer'; + xhr.onload = function xhr_onload() { + if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0 + onload(xhr.response); + return; + } + onerror(); + }; + xhr.onerror = onerror; + xhr.send(null); + }; + + + + + } + + //setWindowTitle = function(title) { document.title = title }; +} else +{ +} + + +// Set up the out() and err() hooks, which are how we can print to stdout or +// stderr, respectively. +var out = Module['print'] || console.log.bind(console); +var err = Module['printErr'] || console.warn.bind(console); + +// Merge back in the overrides +for (key in moduleOverrides) { + if (moduleOverrides.hasOwnProperty(key)) { + Module[key] = moduleOverrides[key]; + } +} +// Free the object hierarchy contained in the overrides, this lets the GC +// reclaim data used e.g. in memoryInitializerRequest, which is a large typed array. +moduleOverrides = null; + +// Emit code to handle expected values on the Module object. This applies Module.x +// to the proper local x. This has two benefits: first, we only emit it if it is +// expected to arrive, and second, by using a local everywhere else that can be +// minified. +if (Module['arguments']) arguments_ = Module['arguments']; +if (Module['thisProgram']) thisProgram = Module['thisProgram']; +if (Module['quit']) quit_ = Module['quit']; + +// perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message + + + + + +// {{PREAMBLE_ADDITIONS}} + +var STACK_ALIGN = 16; + +function dynamicAlloc(size) { + var ret = HEAP32[DYNAMICTOP_PTR>>2]; + var end = (ret + size + 15) & -16; + HEAP32[DYNAMICTOP_PTR>>2] = end; + return ret; +} + +function alignMemory(size, factor) { + if (!factor) factor = STACK_ALIGN; // stack alignment (16-byte) by default + return Math.ceil(size / factor) * factor; +} + +function getNativeTypeSize(type) { + switch (type) { + case 'i1': case 'i8': return 1; + case 'i16': return 2; + case 'i32': return 4; + case 'i64': return 8; + case 'float': return 4; + case 'double': return 8; + default: { + if (type[type.length-1] === '*') { + return 4; // A pointer + } else if (type[0] === 'i') { + var bits = Number(type.substr(1)); + assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type); + return bits / 8; + } else { + return 0; + } + } + } +} + +function warnOnce(text) { + if (!warnOnce.shown) warnOnce.shown = {}; + if (!warnOnce.shown[text]) { + warnOnce.shown[text] = 1; + err(text); + } +} + + + + + + + + +// Wraps a JS function as a wasm function with a given signature. +function convertJsFunctionToWasm(func, sig) { + + // If the type reflection proposal is available, use the new + // "WebAssembly.Function" constructor. + // Otherwise, construct a minimal wasm module importing the JS function and + // re-exporting it. + if (typeof WebAssembly.Function === "function") { + var typeNames = { + 'i': 'i32', + 'j': 'i64', + 'f': 'f32', + 'd': 'f64' + }; + var type = { + parameters: [], + results: sig[0] == 'v' ? [] : [typeNames[sig[0]]] + }; + for (var i = 1; i < sig.length; ++i) { + type.parameters.push(typeNames[sig[i]]); + } + return new WebAssembly.Function(type, func); + } + + // The module is static, with the exception of the type section, which is + // generated based on the signature passed in. + var typeSection = [ + 0x01, // id: section, + 0x00, // length: 0 (placeholder) + 0x01, // count: 1 + 0x60, // form: func + ]; + var sigRet = sig.slice(0, 1); + var sigParam = sig.slice(1); + var typeCodes = { + 'i': 0x7f, // i32 + 'j': 0x7e, // i64 + 'f': 0x7d, // f32 + 'd': 0x7c, // f64 + }; + + // Parameters, length + signatures + typeSection.push(sigParam.length); + for (var i = 0; i < sigParam.length; ++i) { + typeSection.push(typeCodes[sigParam[i]]); + } + + // Return values, length + signatures + // With no multi-return in MVP, either 0 (void) or 1 (anything else) + if (sigRet == 'v') { + typeSection.push(0x00); + } else { + typeSection = typeSection.concat([0x01, typeCodes[sigRet]]); + } + + // Write the overall length of the type section back into the section header + // (excepting the 2 bytes for the section id and length) + typeSection[1] = typeSection.length - 2; + + // Rest of the module is static + var bytes = new Uint8Array([ + 0x00, 0x61, 0x73, 0x6d, // magic ("\0asm") + 0x01, 0x00, 0x00, 0x00, // version: 1 + ].concat(typeSection, [ + 0x02, 0x07, // import section + // (import "e" "f" (func 0 (type 0))) + 0x01, 0x01, 0x65, 0x01, 0x66, 0x00, 0x00, + 0x07, 0x05, // export section + // (export "f" (func 0 (type 0))) + 0x01, 0x01, 0x66, 0x00, 0x00, + ])); + + // We can compile this wasm module synchronously because it is very small. + // This accepts an import (at "e.f"), that it reroutes to an export (at "f") + var module = new WebAssembly.Module(bytes); + var instance = new WebAssembly.Instance(module, { + 'e': { + 'f': func + } + }); + var wrappedFunc = instance.exports['f']; + return wrappedFunc; +} + +var freeTableIndexes = []; + +// Weak map of functions in the table to their indexes, created on first use. +var functionsInTableMap; + +// Add a wasm function to the table. +function addFunctionWasm(func, sig) { + var table = wasmTable; + + // Check if the function is already in the table, to ensure each function + // gets a unique index. First, create the map if this is the first use. + if (!functionsInTableMap) { + functionsInTableMap = new WeakMap(); + for (var i = 0; i < table.length; i++) { + var item = table.get(i); + // Ignore null values. + if (item) { + functionsInTableMap.set(item, i); + } + } + } + if (functionsInTableMap.has(func)) { + return functionsInTableMap.get(func); + } + + // It's not in the table, add it now. + + + var ret; + // Reuse a free index if there is one, otherwise grow. + if (freeTableIndexes.length) { + ret = freeTableIndexes.pop(); + } else { + ret = table.length; + // Grow the table + try { + table.grow(1); + } catch (err) { + if (!(err instanceof RangeError)) { + throw err; + } + throw 'Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.'; + } + } + + // Set the new value. + try { + // Attempting to call this with JS function will cause of table.set() to fail + table.set(ret, func); + } catch (err) { + if (!(err instanceof TypeError)) { + throw err; + } + var wrapped = convertJsFunctionToWasm(func, sig); + table.set(ret, wrapped); + } + + functionsInTableMap.set(func, ret); + + return ret; +} + +function removeFunctionWasm(index) { + functionsInTableMap.delete(wasmTable.get(index)); + freeTableIndexes.push(index); +} + +// 'sig' parameter is required for the llvm backend but only when func is not +// already a WebAssembly function. +function addFunction(func, sig) { + + return addFunctionWasm(func, sig); +} + +function removeFunction(index) { + removeFunctionWasm(index); +} + + + +var funcWrappers = {}; + +function getFuncWrapper(func, sig) { + if (!func) return; // on null pointer, return undefined + assert(sig); + if (!funcWrappers[sig]) { + funcWrappers[sig] = {}; + } + var sigCache = funcWrappers[sig]; + if (!sigCache[func]) { + // optimize away arguments usage in common cases + if (sig.length === 1) { + sigCache[func] = function dynCall_wrapper() { + return dynCall(sig, func); + }; + } else if (sig.length === 2) { + sigCache[func] = function dynCall_wrapper(arg) { + return dynCall(sig, func, [arg]); + }; + } else { + // general case + sigCache[func] = function dynCall_wrapper() { + return dynCall(sig, func, Array.prototype.slice.call(arguments)); + }; + } + } + return sigCache[func]; +} + + + + + + + +function makeBigInt(low, high, unsigned) { + return unsigned ? ((+((low>>>0)))+((+((high>>>0)))*4294967296.0)) : ((+((low>>>0)))+((+((high|0)))*4294967296.0)); +} + +/** @param {Array=} args */ +function dynCall(sig, ptr, args) { + if (args && args.length) { + return Module['dynCall_' + sig].apply(null, [ptr].concat(args)); + } else { + return Module['dynCall_' + sig].call(null, ptr); + } +} + +var tempRet0 = 0; + +var setTempRet0 = function(value) { + tempRet0 = value; +}; + +var getTempRet0 = function() { + return tempRet0; +}; + + +// The address globals begin at. Very low in memory, for code size and optimization opportunities. +// Above 0 is static memory, starting with globals. +// Then the stack. +// Then 'dynamic' memory for sbrk. +var GLOBAL_BASE = 1024; + + + + + +// === Preamble library stuff === + +// Documentation for the public APIs defined in this file must be updated in: +// site/source/docs/api_reference/preamble.js.rst +// A prebuilt local version of the documentation is available at: +// site/build/text/docs/api_reference/preamble.js.txt +// You can also build docs locally as HTML or other formats in site/ +// An online HTML version (which may be of a different version of Emscripten) +// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html + + +var wasmBinary;if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']; +var noExitRuntime;if (Module['noExitRuntime']) noExitRuntime = Module['noExitRuntime']; + + +if (typeof WebAssembly !== 'object') { + err('no native wasm support detected'); +} + + + + +// In MINIMAL_RUNTIME, setValue() and getValue() are only available when building with safe heap enabled, for heap safety checking. +// In traditional runtime, setValue() and getValue() are always available (although their use is highly discouraged due to perf penalties) + +/** @param {number} ptr + @param {number} value + @param {string} type + @param {number|boolean=} noSafe */ +function setValue(ptr, value, type, noSafe) { + type = type || 'i8'; + if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit + switch(type) { + case 'i1': HEAP8[((ptr)>>0)]=value; break; + case 'i8': HEAP8[((ptr)>>0)]=value; break; + case 'i16': HEAP16[((ptr)>>1)]=value; break; + case 'i32': HEAP32[((ptr)>>2)]=value; break; + case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math_min((+(Math_floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break; + case 'float': HEAPF32[((ptr)>>2)]=value; break; + case 'double': HEAPF64[((ptr)>>3)]=value; break; + default: abort('invalid type for setValue: ' + type); + } +} + +/** @param {number} ptr + @param {string} type + @param {number|boolean=} noSafe */ +function getValue(ptr, type, noSafe) { + type = type || 'i8'; + if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit + switch(type) { + case 'i1': return HEAP8[((ptr)>>0)]; + case 'i8': return HEAP8[((ptr)>>0)]; + case 'i16': return HEAP16[((ptr)>>1)]; + case 'i32': return HEAP32[((ptr)>>2)]; + case 'i64': return HEAP32[((ptr)>>2)]; + case 'float': return HEAPF32[((ptr)>>2)]; + case 'double': return HEAPF64[((ptr)>>3)]; + default: abort('invalid type for getValue: ' + type); + } + return null; +} + + + + + + +// Wasm globals + +var wasmMemory; + +// In fastcomp asm.js, we don't need a wasm Table at all. +// In the wasm backend, we polyfill the WebAssembly object, +// so this creates a (non-native-wasm) table for us. +var wasmTable = new WebAssembly.Table({ + 'initial': 4, + 'maximum': 4 + 0, + 'element': 'anyfunc' +}); + + +//======================================== +// Runtime essentials +//======================================== + +// whether we are quitting the application. no code should run after this. +// set in exit() and abort() +var ABORT = false; + +// set by exit() and abort(). Passed to 'onExit' handler. +// NOTE: This is also used as the process return code code in shell environments +// but only when noExitRuntime is false. +var EXITSTATUS = 0; + +/** @type {function(*, string=)} */ +function assert(condition, text) { + if (!condition) { + abort('Assertion failed: ' + text); + } +} + +// Returns the C function with a specified identifier (for C++, you need to do manual name mangling) +function getCFunc(ident) { + var func = Module['_' + ident]; // closure exported function + assert(func, 'Cannot call unknown function ' + ident + ', make sure it is exported'); + return func; +} + +// C calling interface. +/** @param {string|null=} returnType + @param {Array=} argTypes + @param {Arguments|Array=} args + @param {Object=} opts */ +function ccall(ident, returnType, argTypes, args, opts) { + // For fast lookup of conversion functions + var toC = { + 'string': function(str) { + var ret = 0; + if (str !== null && str !== undefined && str !== 0) { // null string + // at most 4 bytes per UTF-8 code point, +1 for the trailing '\0' + var len = (str.length << 2) + 1; + ret = stackAlloc(len); + stringToUTF8(str, ret, len); + } + return ret; + }, + 'array': function(arr) { + var ret = stackAlloc(arr.length); + writeArrayToMemory(arr, ret); + return ret; + } + }; + + function convertReturnValue(ret) { + if (returnType === 'string') return UTF8ToString(ret); + if (returnType === 'boolean') return Boolean(ret); + return ret; + } + + var func = getCFunc(ident); + var cArgs = []; + var stack = 0; + if (args) { + for (var i = 0; i < args.length; i++) { + var converter = toC[argTypes[i]]; + if (converter) { + if (stack === 0) stack = stackSave(); + cArgs[i] = converter(args[i]); + } else { + cArgs[i] = args[i]; + } + } + } + var ret = func.apply(null, cArgs); + + ret = convertReturnValue(ret); + if (stack !== 0) stackRestore(stack); + return ret; +} + +/** @param {string=} returnType + @param {Array=} argTypes + @param {Object=} opts */ +function cwrap(ident, returnType, argTypes, opts) { + argTypes = argTypes || []; + // When the function takes numbers and returns a number, we can just return + // the original function + var numericArgs = argTypes.every(function(type){ return type === 'number'}); + var numericRet = returnType !== 'string'; + if (numericRet && numericArgs && !opts) { + return getCFunc(ident); + } + return function() { + return ccall(ident, returnType, argTypes, arguments, opts); + } +} + +var ALLOC_NORMAL = 0; // Tries to use _malloc() +var ALLOC_STACK = 1; // Lives for the duration of the current function call +var ALLOC_DYNAMIC = 2; // Cannot be freed except through sbrk +var ALLOC_NONE = 3; // Do not allocate + +// allocate(): This is for internal use. You can use it yourself as well, but the interface +// is a little tricky (see docs right below). The reason is that it is optimized +// for multiple syntaxes to save space in generated code. So you should +// normally not use allocate(), and instead allocate memory using _malloc(), +// initialize it with setValue(), and so forth. +// @slab: An array of data, or a number. If a number, then the size of the block to allocate, +// in *bytes* (note that this is sometimes confusing: the next parameter does not +// affect this!) +// @types: Either an array of types, one for each byte (or 0 if no type at that position), +// or a single type which is used for the entire block. This only matters if there +// is initial data - if @slab is a number, then this does not matter at all and is +// ignored. +// @allocator: How to allocate memory, see ALLOC_* +/** @type {function((TypedArray|Array|number), string, number, number=)} */ +function allocate(slab, types, allocator, ptr) { + var zeroinit, size; + if (typeof slab === 'number') { + zeroinit = true; + size = slab; + } else { + zeroinit = false; + size = slab.length; + } + + var singleType = typeof types === 'string' ? types : null; + + var ret; + if (allocator == ALLOC_NONE) { + ret = ptr; + } else { + ret = [_malloc, + stackAlloc, + dynamicAlloc][allocator](Math.max(size, singleType ? 1 : types.length)); + } + + if (zeroinit) { + var stop; + ptr = ret; + assert((ret & 3) == 0); + stop = ret + (size & ~3); + for (; ptr < stop; ptr += 4) { + HEAP32[((ptr)>>2)]=0; + } + stop = ret + size; + while (ptr < stop) { + HEAP8[((ptr++)>>0)]=0; + } + return ret; + } + + if (singleType === 'i8') { + if (slab.subarray || slab.slice) { + HEAPU8.set(/** @type {!Uint8Array} */ (slab), ret); + } else { + HEAPU8.set(new Uint8Array(slab), ret); + } + return ret; + } + + var i = 0, type, typeSize, previousType; + while (i < size) { + var curr = slab[i]; + + type = singleType || types[i]; + if (type === 0) { + i++; + continue; + } + + if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later + + setValue(ret+i, curr, type); + + // no need to look up size unless type changes, so cache it + if (previousType !== type) { + typeSize = getNativeTypeSize(type); + previousType = type; + } + i += typeSize; + } + + return ret; +} + +// Allocate memory during any stage of startup - static memory early on, dynamic memory later, malloc when ready +function getMemory(size) { + if (!runtimeInitialized) return dynamicAlloc(size); + return _malloc(size); +} + + + + +// runtime_strings.js: Strings related runtime functions that are part of both MINIMAL_RUNTIME and regular runtime. + +// Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the given array that contains uint8 values, returns +// a copy of that string as a Javascript String object. + +var UTF8Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined; + +/** + * @param {number} idx + * @param {number=} maxBytesToRead + * @return {string} + */ +function UTF8ArrayToString(heap, idx, maxBytesToRead) { + var endIdx = idx + maxBytesToRead; + var endPtr = idx; + // TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself. + // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage. + // (As a tiny code save trick, compare endPtr against endIdx using a negation, so that undefined means Infinity) + while (heap[endPtr] && !(endPtr >= endIdx)) ++endPtr; + + if (endPtr - idx > 16 && heap.subarray && UTF8Decoder) { + return UTF8Decoder.decode(heap.subarray(idx, endPtr)); + } else { + var str = ''; + // If building with TextDecoder, we have already computed the string length above, so test loop end condition against that + while (idx < endPtr) { + // For UTF8 byte structure, see: + // http://en.wikipedia.org/wiki/UTF-8#Description + // https://www.ietf.org/rfc/rfc2279.txt + // https://tools.ietf.org/html/rfc3629 + var u0 = heap[idx++]; + if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; } + var u1 = heap[idx++] & 63; + if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; } + var u2 = heap[idx++] & 63; + if ((u0 & 0xF0) == 0xE0) { + u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; + } else { + u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heap[idx++] & 63); + } + + if (u0 < 0x10000) { + str += String.fromCharCode(u0); + } else { + var ch = u0 - 0x10000; + str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); + } + } + } + return str; +} + +// Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the emscripten HEAP, returns a +// copy of that string as a Javascript String object. +// maxBytesToRead: an optional length that specifies the maximum number of bytes to read. You can omit +// this parameter to scan the string until the first \0 byte. If maxBytesToRead is +// passed, and the string at [ptr, ptr+maxBytesToReadr[ contains a null byte in the +// middle, then the string will cut short at that byte index (i.e. maxBytesToRead will +// not produce a string of exact length [ptr, ptr+maxBytesToRead[) +// N.B. mixing frequent uses of UTF8ToString() with and without maxBytesToRead may +// throw JS JIT optimizations off, so it is worth to consider consistently using one +// style or the other. +/** + * @param {number} ptr + * @param {number=} maxBytesToRead + * @return {string} + */ +function UTF8ToString(ptr, maxBytesToRead) { + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; +} + +// Copies the given Javascript String object 'str' to the given byte array at address 'outIdx', +// encoded in UTF8 form and null-terminated. The copy will require at most str.length*4+1 bytes of space in the HEAP. +// Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write. +// Parameters: +// str: the Javascript string to copy. +// heap: the array to copy to. Each index in this array is assumed to be one 8-byte element. +// outIdx: The starting offset in the array to begin the copying. +// maxBytesToWrite: The maximum number of bytes this function can write to the array. +// This count should include the null terminator, +// i.e. if maxBytesToWrite=1, only the null terminator will be written and nothing else. +// maxBytesToWrite=0 does not write any bytes to the output, not even the null terminator. +// Returns the number of bytes written, EXCLUDING the null terminator. + +function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { + if (!(maxBytesToWrite > 0)) // Parameter maxBytesToWrite is not optional. Negative values, 0, null, undefined and false each don't write out any bytes. + return 0; + + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629 + var u = str.charCodeAt(i); // possibly a lead surrogate + if (u >= 0xD800 && u <= 0xDFFF) { + var u1 = str.charCodeAt(++i); + u = 0x10000 + ((u & 0x3FF) << 10) | (u1 & 0x3FF); + } + if (u <= 0x7F) { + if (outIdx >= endIdx) break; + heap[outIdx++] = u; + } else if (u <= 0x7FF) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++] = 0xC0 | (u >> 6); + heap[outIdx++] = 0x80 | (u & 63); + } else if (u <= 0xFFFF) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++] = 0xE0 | (u >> 12); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + } else { + if (outIdx + 3 >= endIdx) break; + heap[outIdx++] = 0xF0 | (u >> 18); + heap[outIdx++] = 0x80 | ((u >> 12) & 63); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + } + } + // Null-terminate the pointer to the buffer. + heap[outIdx] = 0; + return outIdx - startIdx; +} + +// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', +// null-terminated and encoded in UTF8 form. The copy will require at most str.length*4+1 bytes of space in the HEAP. +// Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write. +// Returns the number of bytes written, EXCLUDING the null terminator. + +function stringToUTF8(str, outPtr, maxBytesToWrite) { + return stringToUTF8Array(str, HEAPU8,outPtr, maxBytesToWrite); +} + +// Returns the number of bytes the given Javascript string takes if encoded as a UTF8 byte array, EXCLUDING the null terminator byte. +function lengthBytesUTF8(str) { + var len = 0; + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var u = str.charCodeAt(i); // possibly a lead surrogate + if (u >= 0xD800 && u <= 0xDFFF) u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF); + if (u <= 0x7F) ++len; + else if (u <= 0x7FF) len += 2; + else if (u <= 0xFFFF) len += 3; + else len += 4; + } + return len; +} + + + + + +// runtime_strings_extra.js: Strings related runtime functions that are available only in regular runtime. + +// Given a pointer 'ptr' to a null-terminated ASCII-encoded string in the emscripten HEAP, returns +// a copy of that string as a Javascript String object. + +function AsciiToString(ptr) { + var str = ''; + while (1) { + var ch = HEAPU8[((ptr++)>>0)]; + if (!ch) return str; + str += String.fromCharCode(ch); + } +} + +// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', +// null-terminated and encoded in ASCII form. The copy will require at most str.length+1 bytes of space in the HEAP. + +function stringToAscii(str, outPtr) { + return writeAsciiToMemory(str, outPtr, false); +} + +// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns +// a copy of that string as a Javascript String object. + +var UTF16Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-16le') : undefined; + +function UTF16ToString(ptr, maxBytesToRead) { + var endPtr = ptr; + // TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself. + // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage. + var idx = endPtr >> 1; + var maxIdx = idx + maxBytesToRead / 2; + // If maxBytesToRead is not passed explicitly, it will be undefined, and this + // will always evaluate to true. This saves on code size. + while (!(idx >= maxIdx) && HEAPU16[idx]) ++idx; + endPtr = idx << 1; + + if (endPtr - ptr > 32 && UTF16Decoder) { + return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr)); + } else { + var i = 0; + + var str = ''; + while (1) { + var codeUnit = HEAP16[(((ptr)+(i*2))>>1)]; + if (codeUnit == 0 || i == maxBytesToRead / 2) return str; + ++i; + // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through. + str += String.fromCharCode(codeUnit); + } + } +} + +// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', +// null-terminated and encoded in UTF16 form. The copy will require at most str.length*4+2 bytes of space in the HEAP. +// Use the function lengthBytesUTF16() to compute the exact number of bytes (excluding null terminator) that this function will write. +// Parameters: +// str: the Javascript string to copy. +// outPtr: Byte address in Emscripten HEAP where to write the string to. +// maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null +// terminator, i.e. if maxBytesToWrite=2, only the null terminator will be written and nothing else. +// maxBytesToWrite<2 does not write any bytes to the output, not even the null terminator. +// Returns the number of bytes written, EXCLUDING the null terminator. + +function stringToUTF16(str, outPtr, maxBytesToWrite) { + // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. + if (maxBytesToWrite === undefined) { + maxBytesToWrite = 0x7FFFFFFF; + } + if (maxBytesToWrite < 2) return 0; + maxBytesToWrite -= 2; // Null terminator. + var startPtr = outPtr; + var numCharsToWrite = (maxBytesToWrite < str.length*2) ? (maxBytesToWrite / 2) : str.length; + for (var i = 0; i < numCharsToWrite; ++i) { + // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP. + var codeUnit = str.charCodeAt(i); // possibly a lead surrogate + HEAP16[((outPtr)>>1)]=codeUnit; + outPtr += 2; + } + // Null-terminate the pointer to the HEAP. + HEAP16[((outPtr)>>1)]=0; + return outPtr - startPtr; +} + +// Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte. + +function lengthBytesUTF16(str) { + return str.length*2; +} + +function UTF32ToString(ptr, maxBytesToRead) { + var i = 0; + + var str = ''; + // If maxBytesToRead is not passed explicitly, it will be undefined, and this + // will always evaluate to true. This saves on code size. + while (!(i >= maxBytesToRead / 4)) { + var utf32 = HEAP32[(((ptr)+(i*4))>>2)]; + if (utf32 == 0) break; + ++i; + // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + if (utf32 >= 0x10000) { + var ch = utf32 - 0x10000; + str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); + } else { + str += String.fromCharCode(utf32); + } + } + return str; +} + +// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', +// null-terminated and encoded in UTF32 form. The copy will require at most str.length*4+4 bytes of space in the HEAP. +// Use the function lengthBytesUTF32() to compute the exact number of bytes (excluding null terminator) that this function will write. +// Parameters: +// str: the Javascript string to copy. +// outPtr: Byte address in Emscripten HEAP where to write the string to. +// maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null +// terminator, i.e. if maxBytesToWrite=4, only the null terminator will be written and nothing else. +// maxBytesToWrite<4 does not write any bytes to the output, not even the null terminator. +// Returns the number of bytes written, EXCLUDING the null terminator. + +function stringToUTF32(str, outPtr, maxBytesToWrite) { + // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. + if (maxBytesToWrite === undefined) { + maxBytesToWrite = 0x7FFFFFFF; + } + if (maxBytesToWrite < 4) return 0; + var startPtr = outPtr; + var endPtr = startPtr + maxBytesToWrite - 4; + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var codeUnit = str.charCodeAt(i); // possibly a lead surrogate + if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) { + var trailSurrogate = str.charCodeAt(++i); + codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF); + } + HEAP32[((outPtr)>>2)]=codeUnit; + outPtr += 4; + if (outPtr + 4 > endPtr) break; + } + // Null-terminate the pointer to the HEAP. + HEAP32[((outPtr)>>2)]=0; + return outPtr - startPtr; +} + +// Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte. + +function lengthBytesUTF32(str) { + var len = 0; + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var codeUnit = str.charCodeAt(i); + if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) ++i; // possibly a lead surrogate, so skip over the tail surrogate. + len += 4; + } + + return len; +} + +// Allocate heap space for a JS string, and write it there. +// It is the responsibility of the caller to free() that memory. +function allocateUTF8(str) { + var size = lengthBytesUTF8(str) + 1; + var ret = _malloc(size); + if (ret) stringToUTF8Array(str, HEAP8, ret, size); + return ret; +} + +// Allocate stack space for a JS string, and write it there. +function allocateUTF8OnStack(str) { + var size = lengthBytesUTF8(str) + 1; + var ret = stackAlloc(size); + stringToUTF8Array(str, HEAP8, ret, size); + return ret; +} + +// Deprecated: This function should not be called because it is unsafe and does not provide +// a maximum length limit of how many bytes it is allowed to write. Prefer calling the +// function stringToUTF8Array() instead, which takes in a maximum length that can be used +// to be secure from out of bounds writes. +/** @deprecated + @param {boolean=} dontAddNull */ +function writeStringToMemory(string, buffer, dontAddNull) { + warnOnce('writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!'); + + var /** @type {number} */ lastChar, /** @type {number} */ end; + if (dontAddNull) { + // stringToUTF8Array always appends null. If we don't want to do that, remember the + // character that existed at the location where the null will be placed, and restore + // that after the write (below). + end = buffer + lengthBytesUTF8(string); + lastChar = HEAP8[end]; + } + stringToUTF8(string, buffer, Infinity); + if (dontAddNull) HEAP8[end] = lastChar; // Restore the value under the null character. +} + +function writeArrayToMemory(array, buffer) { + HEAP8.set(array, buffer); +} + +/** @param {boolean=} dontAddNull */ +function writeAsciiToMemory(str, buffer, dontAddNull) { + for (var i = 0; i < str.length; ++i) { + HEAP8[((buffer++)>>0)]=str.charCodeAt(i); + } + // Null-terminate the pointer to the HEAP. + if (!dontAddNull) HEAP8[((buffer)>>0)]=0; +} + + + +// Memory management + +var PAGE_SIZE = 16384; +var WASM_PAGE_SIZE = 65536; +var ASMJS_PAGE_SIZE = 16777216; + +function alignUp(x, multiple) { + if (x % multiple > 0) { + x += multiple - (x % multiple); + } + return x; +} + +var HEAP, +/** @type {ArrayBuffer} */ + buffer, +/** @type {Int8Array} */ + HEAP8, +/** @type {Uint8Array} */ + HEAPU8, +/** @type {Int16Array} */ + HEAP16, +/** @type {Uint16Array} */ + HEAPU16, +/** @type {Int32Array} */ + HEAP32, +/** @type {Uint32Array} */ + HEAPU32, +/** @type {Float32Array} */ + HEAPF32, +/** @type {Float64Array} */ + HEAPF64; + +function updateGlobalBufferAndViews(buf) { + buffer = buf; + Module['HEAP8'] = HEAP8 = new Int8Array(buf); + Module['HEAP16'] = HEAP16 = new Int16Array(buf); + Module['HEAP32'] = HEAP32 = new Int32Array(buf); + Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf); + Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf); + Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf); + Module['HEAPF32'] = HEAPF32 = new Float32Array(buf); + Module['HEAPF64'] = HEAPF64 = new Float64Array(buf); +} + +var STATIC_BASE = 1024, + STACK_BASE = 5340160, + STACKTOP = STACK_BASE, + STACK_MAX = 97280, + DYNAMIC_BASE = 5340160, + DYNAMICTOP_PTR = 97120; + + + +var TOTAL_STACK = 5242880; + +var INITIAL_INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216; + + + + + + + + + +// In non-standalone/normal mode, we create the memory here. + + + +// Create the main memory. (Note: this isn't used in STANDALONE_WASM mode since the wasm +// memory is created in the wasm, not in JS.) + + if (Module['wasmMemory']) { + wasmMemory = Module['wasmMemory']; + } else + { + wasmMemory = new WebAssembly.Memory({ + 'initial': INITIAL_INITIAL_MEMORY / WASM_PAGE_SIZE + , + 'maximum': 2147483648 / WASM_PAGE_SIZE + }); + } + + +if (wasmMemory) { + buffer = wasmMemory.buffer; +} + +// If the user provides an incorrect length, just use that length instead rather than providing the user to +// specifically provide the memory length with Module['INITIAL_MEMORY']. +INITIAL_INITIAL_MEMORY = buffer.byteLength; +updateGlobalBufferAndViews(buffer); + +HEAP32[DYNAMICTOP_PTR>>2] = DYNAMIC_BASE; + + + + + + + + + + + + + + +function callRuntimeCallbacks(callbacks) { + while(callbacks.length > 0) { + var callback = callbacks.shift(); + if (typeof callback == 'function') { + callback(Module); // Pass the module as the first argument. + continue; + } + var func = callback.func; + if (typeof func === 'number') { + if (callback.arg === undefined) { + Module['dynCall_v'](func); + } else { + Module['dynCall_vi'](func, callback.arg); + } + } else { + func(callback.arg === undefined ? null : callback.arg); + } + } +} + +var __ATPRERUN__ = []; // functions called before the runtime is initialized +var __ATINIT__ = []; // functions called during startup +var __ATMAIN__ = []; // functions called when main() is to be run +var __ATEXIT__ = []; // functions called during shutdown +var __ATPOSTRUN__ = []; // functions called after the main() is called + +var runtimeInitialized = false; +var runtimeExited = false; + + +function preRun() { + + if (Module['preRun']) { + if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']]; + while (Module['preRun'].length) { + addOnPreRun(Module['preRun'].shift()); + } + } + + callRuntimeCallbacks(__ATPRERUN__); +} + +function initRuntime() { + runtimeInitialized = true; + + callRuntimeCallbacks(__ATINIT__); +} + +function preMain() { + + callRuntimeCallbacks(__ATMAIN__); +} + +function exitRuntime() { + runtimeExited = true; +} + +function postRun() { + + if (Module['postRun']) { + if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']]; + while (Module['postRun'].length) { + addOnPostRun(Module['postRun'].shift()); + } + } + + callRuntimeCallbacks(__ATPOSTRUN__); +} + +function addOnPreRun(cb) { + __ATPRERUN__.unshift(cb); +} + +function addOnInit(cb) { + __ATINIT__.unshift(cb); +} + +function addOnPreMain(cb) { + __ATMAIN__.unshift(cb); +} + +function addOnExit(cb) { +} + +function addOnPostRun(cb) { + __ATPOSTRUN__.unshift(cb); +} + +/** @param {number|boolean=} ignore */ +function unSign(value, bits, ignore) { + if (value >= 0) { + return value; + } + return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts + : Math.pow(2, bits) + value; +} +/** @param {number|boolean=} ignore */ +function reSign(value, bits, ignore) { + if (value <= 0) { + return value; + } + var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32 + : Math.pow(2, bits-1); + if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that + // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors + // TODO: In i64 mode 1, resign the two parts separately and safely + value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts + } + return value; +} + + + + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc + + +var Math_abs = Math.abs; +var Math_cos = Math.cos; +var Math_sin = Math.sin; +var Math_tan = Math.tan; +var Math_acos = Math.acos; +var Math_asin = Math.asin; +var Math_atan = Math.atan; +var Math_atan2 = Math.atan2; +var Math_exp = Math.exp; +var Math_log = Math.log; +var Math_sqrt = Math.sqrt; +var Math_ceil = Math.ceil; +var Math_floor = Math.floor; +var Math_pow = Math.pow; +var Math_imul = Math.imul; +var Math_fround = Math.fround; +var Math_round = Math.round; +var Math_min = Math.min; +var Math_max = Math.max; +var Math_clz32 = Math.clz32; +var Math_trunc = Math.trunc; + + + +// A counter of dependencies for calling run(). If we need to +// do asynchronous work before running, increment this and +// decrement it. Incrementing must happen in a place like +// Module.preRun (used by emcc to add file preloading). +// Note that you can add dependencies in preRun, even though +// it happens right before run - run will be postponed until +// the dependencies are met. +var runDependencies = 0; +var runDependencyWatcher = null; +var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled + +function getUniqueRunDependency(id) { + return id; +} + +function addRunDependency(id) { + runDependencies++; + + if (Module['monitorRunDependencies']) { + Module['monitorRunDependencies'](runDependencies); + } + +} + +function removeRunDependency(id) { + runDependencies--; + + if (Module['monitorRunDependencies']) { + Module['monitorRunDependencies'](runDependencies); + } + + if (runDependencies == 0) { + if (runDependencyWatcher !== null) { + clearInterval(runDependencyWatcher); + runDependencyWatcher = null; + } + if (dependenciesFulfilled) { + var callback = dependenciesFulfilled; + dependenciesFulfilled = null; + callback(); // can add another dependenciesFulfilled + } + } +} + +Module["preloadedImages"] = {}; // maps url to image data +Module["preloadedAudios"] = {}; // maps url to audio data + +/** @param {string|number=} what */ +function abort(what) { + if (Module['onAbort']) { + Module['onAbort'](what); + } + + what += ''; + out(what); + err(what); + + ABORT = true; + EXITSTATUS = 1; + + what = 'abort(' + what + '). Build with -s ASSERTIONS=1 for more info.'; + + // Throw a wasm runtime error, because a JS error might be seen as a foreign + // exception, which means we'd run destructors on it. We need the error to + // simply make the program stop. + throw new WebAssembly.RuntimeError(what); +} + + +var memoryInitializer = null; + + + + + + + + + + + + +function hasPrefix(str, prefix) { + return String.prototype.startsWith ? + str.startsWith(prefix) : + str.indexOf(prefix) === 0; +} + +// Prefix of data URIs emitted by SINGLE_FILE and related options. +var dataURIPrefix = 'data:application/octet-stream;base64,'; + +// Indicates whether filename is a base64 data URI. +function isDataURI(filename) { + return hasPrefix(filename, dataURIPrefix); +} + +var fileURIPrefix = "file://"; + +// Indicates whether filename is delivered via file protocol (as opposed to http/https) +function isFileURI(filename) { + return hasPrefix(filename, fileURIPrefix); +} + + + + +var wasmBinaryFile = 'rnn_denoise.wasm'; +if (!isDataURI(wasmBinaryFile)) { + wasmBinaryFile = locateFile(wasmBinaryFile); +} + +function getBinary() { + try { + if (wasmBinary) { + return new Uint8Array(wasmBinary); + } + + if (readBinary) { + return readBinary(wasmBinaryFile); + } else { + throw "both async and sync fetching of the wasm failed"; + } + } + catch (err) { + abort(err); + } +} + +function getBinaryPromise() { + // If we don't have the binary yet, and have the Fetch api, use that; + // in some environments, like Electron's render process, Fetch api may be present, but have a different context than expected, let's only use it on the Web + if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && typeof fetch === 'function' + // Let's not use fetch to get objects over file:// as it's most likely Cordova which doesn't support fetch for file:// + && !isFileURI(wasmBinaryFile) + ) { + return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) { + if (!response['ok']) { + throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; + } + return response['arrayBuffer'](); + }).catch(function () { + return getBinary(); + }); + } + // Otherwise, getBinary should be able to get it synchronously + return new Promise(function(resolve, reject) { + resolve(getBinary()); + }); +} + + + +// Create the wasm instance. +// Receives the wasm imports, returns the exports. +function createWasm() { + // prepare imports + var info = { + 'env': asmLibraryArg, + 'wasi_snapshot_preview1': asmLibraryArg + }; + // Load the wasm module and create an instance of using native support in the JS engine. + // handle a generated wasm instance, receiving its exports and + // performing other necessary setup + /** @param {WebAssembly.Module=} module*/ + function receiveInstance(instance, module) { + var exports = instance.exports; + Module['asm'] = exports; + removeRunDependency('wasm-instantiate'); + } + // we can't run yet (except in a pthread, where we have a custom sync instantiator) + addRunDependency('wasm-instantiate'); + + + function receiveInstantiatedSource(output) { + // 'output' is a WebAssemblyInstantiatedSource object which has both the module and instance. + // receiveInstance() will swap in the exports (to Module.asm) so they can be called + // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line. + // When the regression is fixed, can restore the above USE_PTHREADS-enabled path. + receiveInstance(output['instance']); + } + + + function instantiateArrayBuffer(receiver) { + return getBinaryPromise().then(function(binary) { + return WebAssembly.instantiate(binary, info); + }).then(receiver, function(reason) { + err('failed to asynchronously prepare wasm: ' + reason); + abort(reason); + }); + } + + // Prefer streaming instantiation if available. + function instantiateAsync() { + if (!wasmBinary && + typeof WebAssembly.instantiateStreaming === 'function' && + !isDataURI(wasmBinaryFile) && + // Don't use streaming for file:// delivered objects in a webview, fetch them synchronously. + !isFileURI(wasmBinaryFile) && + typeof fetch === 'function') { + fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function (response) { + var result = WebAssembly.instantiateStreaming(response, info); + return result.then(receiveInstantiatedSource, function(reason) { + // We expect the most common failure cause to be a bad MIME type for the binary, + // in which case falling back to ArrayBuffer instantiation should work. + err('wasm streaming compile failed: ' + reason); + err('falling back to ArrayBuffer instantiation'); + return instantiateArrayBuffer(receiveInstantiatedSource); + }); + }); + } else { + return instantiateArrayBuffer(receiveInstantiatedSource); + } + } + // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback + // to manually instantiate the Wasm module themselves. This allows pages to run the instantiation parallel + // to any other async startup actions they are performing. + if (Module['instantiateWasm']) { + try { + var exports = Module['instantiateWasm'](info, receiveInstance); + return exports; + } catch(e) { + err('Module.instantiateWasm callback failed with error: ' + e); + return false; + } + } + + instantiateAsync(); + return {}; // no exports yet; we'll fill them in later +} + + +// Globals used by JS i64 conversions +var tempDouble; +var tempI64; + +// === Body === + +var ASM_CONSTS = { + +}; + + + + +// STATICTOP = STATIC_BASE + 96256; +/* global initializers */ __ATINIT__.push({ func: function() { ___wasm_call_ctors() } }); + + + + +/* no memory initializer */ +// {{PRE_LIBRARY}} + + + function demangle(func) { + return func; + } + + function demangleAll(text) { + var regex = + /\b_Z[\w\d_]+/g; + return text.replace(regex, + function(x) { + var y = demangle(x); + return x === y ? x : (y + ' [' + x + ']'); + }); + } + + function jsStackTrace() { + var err = new Error(); + if (!err.stack) { + // IE10+ special cases: It does have callstack info, but it is only populated if an Error object is thrown, + // so try that as a special-case. + try { + throw new Error(); + } catch(e) { + err = e; + } + if (!err.stack) { + return '(no stack trace available)'; + } + } + return err.stack.toString(); + } + + function stackTrace() { + var js = jsStackTrace(); + if (Module['extraStackTrace']) js += '\n' + Module['extraStackTrace'](); + return demangleAll(js); + } + + + var _emscripten_get_now;if (ENVIRONMENT_IS_NODE) { + _emscripten_get_now = function() { + var t = process['hrtime'](); + return t[0] * 1e3 + t[1] / 1e6; + }; + } else if (typeof dateNow !== 'undefined') { + _emscripten_get_now = dateNow; + } else _emscripten_get_now = function() { return performance.now(); } + ; + + var _emscripten_get_now_is_monotonic=true;; + + function setErrNo(value) { + HEAP32[((___errno_location())>>2)]=value; + return value; + }function _clock_gettime(clk_id, tp) { + // int clock_gettime(clockid_t clk_id, struct timespec *tp); + var now; + if (clk_id === 0) { + now = Date.now(); + } else if ((clk_id === 1 || clk_id === 4) && _emscripten_get_now_is_monotonic) { + now = _emscripten_get_now(); + } else { + setErrNo(28); + return -1; + } + HEAP32[((tp)>>2)]=(now/1000)|0; // seconds + HEAP32[(((tp)+(4))>>2)]=((now % 1000)*1000*1000)|0; // nanoseconds + return 0; + } + + function _emscripten_get_sbrk_ptr() { + return 97120; + } + + function _emscripten_memcpy_big(dest, src, num) { + HEAPU8.copyWithin(dest, src, src + num); + } + + + function _emscripten_get_heap_size() { + return HEAPU8.length; + } + + function emscripten_realloc_buffer(size) { + try { + // round size grow request up to wasm page size (fixed 64KB per spec) + wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16); // .grow() takes a delta compared to the previous size + updateGlobalBufferAndViews(wasmMemory.buffer); + return 1 /*success*/; + } catch(e) { + } + }function _emscripten_resize_heap(requestedSize) { + requestedSize = requestedSize >>> 0; + var oldSize = _emscripten_get_heap_size(); + // With pthreads, races can happen (another thread might increase the size in between), so return a failure, and let the caller retry. + + + var PAGE_MULTIPLE = 65536; + + // Memory resize rules: + // 1. When resizing, always produce a resized heap that is at least 16MB (to avoid tiny heap sizes receiving lots of repeated resizes at startup) + // 2. Always increase heap size to at least the requested size, rounded up to next page multiple. + // 3a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap geometrically: increase the heap size according to + // MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), + // At most overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB). + // 3b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap linearly: increase the heap size by at least MEMORY_GROWTH_LINEAR_STEP bytes. + // 4. Max size for the heap is capped at 2048MB-PAGE_MULTIPLE, or by MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest + // 5. If we were unable to allocate as much memory, it may be due to over-eager decision to excessively reserve due to (3) above. + // Hence if an allocation fails, cut down on the amount of excess growth, in an attempt to succeed to perform a smaller allocation. + + // A limit was set for how much we can grow. We should not exceed that + // (the wasm binary specifies it, so if we tried, we'd fail anyhow). + var maxHeapSize = 2147483648; + if (requestedSize > maxHeapSize) { + return false; + } + + var minHeapSize = 16777216; + + // Loop through potential heap size increases. If we attempt a too eager reservation that fails, cut down on the + // attempted size and reserve a smaller bump instead. (max 3 times, chosen somewhat arbitrarily) + for(var cutDown = 1; cutDown <= 4; cutDown *= 2) { + var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); // ensure geometric growth + // but limit overreserving (default to capping at +96MB overgrowth at most) + overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296 ); + + + var newSize = Math.min(maxHeapSize, alignUp(Math.max(minHeapSize, requestedSize, overGrownHeapSize), PAGE_MULTIPLE)); + + var replacement = emscripten_realloc_buffer(newSize); + if (replacement) { + + return true; + } + } + return false; + } + + + + var PATH={splitPath:function(filename) { + var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; + return splitPathRe.exec(filename).slice(1); + },normalizeArray:function(parts, allowAboveRoot) { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up; up--) { + parts.unshift('..'); + } + } + return parts; + },normalize:function(path) { + var isAbsolute = path.charAt(0) === '/', + trailingSlash = path.substr(-1) === '/'; + // Normalize the path + path = PATH.normalizeArray(path.split('/').filter(function(p) { + return !!p; + }), !isAbsolute).join('/'); + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + return (isAbsolute ? '/' : '') + path; + },dirname:function(path) { + var result = PATH.splitPath(path), + root = result[0], + dir = result[1]; + if (!root && !dir) { + // No dirname whatsoever + return '.'; + } + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.substr(0, dir.length - 1); + } + return root + dir; + },basename:function(path) { + // EMSCRIPTEN return '/'' for '/', not an empty string + if (path === '/') return '/'; + var lastSlash = path.lastIndexOf('/'); + if (lastSlash === -1) return path; + return path.substr(lastSlash+1); + },extname:function(path) { + return PATH.splitPath(path)[3]; + },join:function() { + var paths = Array.prototype.slice.call(arguments, 0); + return PATH.normalize(paths.join('/')); + },join2:function(l, r) { + return PATH.normalize(l + '/' + r); + }};var SYSCALLS={mappings:{},buffers:[null,[],[]],printChar:function(stream, curr) { + var buffer = SYSCALLS.buffers[stream]; + if (curr === 0 || curr === 10) { + (stream === 1 ? out : err)(UTF8ArrayToString(buffer, 0)); + buffer.length = 0; + } else { + buffer.push(curr); + } + },varargs:undefined,get:function() { + SYSCALLS.varargs += 4; + var ret = HEAP32[(((SYSCALLS.varargs)-(4))>>2)]; + return ret; + },getStr:function(ptr) { + var ret = UTF8ToString(ptr); + return ret; + },get64:function(low, high) { + return low; + }};function _fd_close(fd) { + return 0; + } + + function _fd_seek(fd, offset_low, offset_high, whence, newOffset) { + } + + + function flush_NO_FILESYSTEM() { + // flush anything remaining in the buffers during shutdown + if (typeof _fflush !== 'undefined') _fflush(0); + var buffers = SYSCALLS.buffers; + if (buffers[1].length) SYSCALLS.printChar(1, 10); + if (buffers[2].length) SYSCALLS.printChar(2, 10); + }function _fd_write(fd, iov, iovcnt, pnum) { + // hack to support printf in SYSCALLS_REQUIRE_FILESYSTEM=0 + var num = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAP32[(((iov)+(i*8))>>2)]; + var len = HEAP32[(((iov)+(i*8 + 4))>>2)]; + for (var j = 0; j < len; j++) { + SYSCALLS.printChar(fd, HEAPU8[ptr+j]); + } + num += len; + } + HEAP32[((pnum)>>2)]=num + return 0; + } + + function _setTempRet0($i) { + setTempRet0(($i) | 0); + } +var ASSERTIONS = false; + + + +/** @type {function(string, boolean=, number=)} */ +function intArrayFromString(stringy, dontAddNull, length) { + var len = length > 0 ? length : lengthBytesUTF8(stringy)+1; + var u8array = new Array(len); + var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length); + if (dontAddNull) u8array.length = numBytesWritten; + return u8array; +} + +function intArrayToString(array) { + var ret = []; + for (var i = 0; i < array.length; i++) { + var chr = array[i]; + if (chr > 0xFF) { + if (ASSERTIONS) { + assert(false, 'Character code ' + chr + ' (' + String.fromCharCode(chr) + ') at offset ' + i + ' not in 0x00-0xFF.'); + } + chr &= 0xFF; + } + ret.push(String.fromCharCode(chr)); + } + return ret.join(''); +} + + +var asmGlobalArg = {}; +var asmLibraryArg = { "clock_gettime": _clock_gettime, "emscripten_get_sbrk_ptr": _emscripten_get_sbrk_ptr, "emscripten_memcpy_big": _emscripten_memcpy_big, "emscripten_resize_heap": _emscripten_resize_heap, "fd_close": _fd_close, "fd_seek": _fd_seek, "fd_write": _fd_write, "memory": wasmMemory, "setTempRet0": _setTempRet0, "table": wasmTable }; +var asm = createWasm(); +/** @type {function(...*):?} */ +var ___wasm_call_ctors = Module["___wasm_call_ctors"] = function() { + return (___wasm_call_ctors = Module["___wasm_call_ctors"] = Module["asm"]["__wasm_call_ctors"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _rnnoise_get_size = Module["_rnnoise_get_size"] = function() { + return (_rnnoise_get_size = Module["_rnnoise_get_size"] = Module["asm"]["rnnoise_get_size"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _rnnoise_init = Module["_rnnoise_init"] = function() { + return (_rnnoise_init = Module["_rnnoise_init"] = Module["asm"]["rnnoise_init"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _rnnoise_create = Module["_rnnoise_create"] = function() { + return (_rnnoise_create = Module["_rnnoise_create"] = Module["asm"]["rnnoise_create"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _malloc = Module["_malloc"] = function() { + return (_malloc = Module["_malloc"] = Module["asm"]["malloc"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _rnnoise_destroy = Module["_rnnoise_destroy"] = function() { + return (_rnnoise_destroy = Module["_rnnoise_destroy"] = Module["asm"]["rnnoise_destroy"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _free = Module["_free"] = function() { + return (_free = Module["_free"] = Module["asm"]["free"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _rnnoise_process_frame = Module["_rnnoise_process_frame"] = function() { + return (_rnnoise_process_frame = Module["_rnnoise_process_frame"] = Module["asm"]["rnnoise_process_frame"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _denoise_proc = Module["_denoise_proc"] = function() { + return (_denoise_proc = Module["_denoise_proc"] = Module["asm"]["denoise_proc"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _rnnDenoise_rawmem = Module["_rnnDenoise_rawmem"] = function() { + return (_rnnDenoise_rawmem = Module["_rnnDenoise_rawmem"] = Module["asm"]["rnnDenoise_rawmem"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _rnnDenoise_rawmem_perf = Module["_rnnDenoise_rawmem_perf"] = function() { + return (_rnnDenoise_rawmem_perf = Module["_rnnDenoise_rawmem_perf"] = Module["asm"]["rnnDenoise_rawmem_perf"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _get_rnnDenoise_rawmem_time = Module["_get_rnnDenoise_rawmem_time"] = function() { + return (_get_rnnDenoise_rawmem_time = Module["_get_rnnDenoise_rawmem_time"] = Module["asm"]["get_rnnDenoise_rawmem_time"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _getResultPointer = Module["_getResultPointer"] = function() { + return (_getResultPointer = Module["_getResultPointer"] = Module["asm"]["getResultPointer"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _getResultSize = Module["_getResultSize"] = function() { + return (_getResultSize = Module["_getResultSize"] = Module["asm"]["getResultSize"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _getsampleRate = Module["_getsampleRate"] = function() { + return (_getsampleRate = Module["_getsampleRate"] = Module["asm"]["getsampleRate"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _getchannels = Module["_getchannels"] = function() { + return (_getchannels = Module["_getchannels"] = Module["asm"]["getchannels"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _getsampleCount = Module["_getsampleCount"] = function() { + return (_getsampleCount = Module["_getsampleCount"] = Module["asm"]["getsampleCount"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _freeBuffer = Module["_freeBuffer"] = function() { + return (_freeBuffer = Module["_freeBuffer"] = Module["asm"]["freeBuffer"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var _main = Module["_main"] = function() { + return (_main = Module["_main"] = Module["asm"]["main"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var ___errno_location = Module["___errno_location"] = function() { + return (___errno_location = Module["___errno_location"] = Module["asm"]["__errno_location"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var stackSave = Module["stackSave"] = function() { + return (stackSave = Module["stackSave"] = Module["asm"]["stackSave"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var stackRestore = Module["stackRestore"] = function() { + return (stackRestore = Module["stackRestore"] = Module["asm"]["stackRestore"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var stackAlloc = Module["stackAlloc"] = function() { + return (stackAlloc = Module["stackAlloc"] = Module["asm"]["stackAlloc"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var __growWasmMemory = Module["__growWasmMemory"] = function() { + return (__growWasmMemory = Module["__growWasmMemory"] = Module["asm"]["__growWasmMemory"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var dynCall_ii = Module["dynCall_ii"] = function() { + return (dynCall_ii = Module["dynCall_ii"] = Module["asm"]["dynCall_ii"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var dynCall_iiii = Module["dynCall_iiii"] = function() { + return (dynCall_iiii = Module["dynCall_iiii"] = Module["asm"]["dynCall_iiii"]).apply(null, arguments); +}; + +/** @type {function(...*):?} */ +var dynCall_jiji = Module["dynCall_jiji"] = function() { + return (dynCall_jiji = Module["dynCall_jiji"] = Module["asm"]["dynCall_jiji"]).apply(null, arguments); +}; + + + + + +// === Auto-generated postamble setup entry stuff === + + + + + +Module["cwrap"] = cwrap; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +var calledRun; + +/** + * @constructor + * @this {ExitStatus} + */ +function ExitStatus(status) { + this.name = "ExitStatus"; + this.message = "Program terminated with exit(" + status + ")"; + this.status = status; +} + +var calledMain = false; + + +dependenciesFulfilled = function runCaller() { + // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false) + if (!calledRun) run(); + if (!calledRun) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled +}; + +function callMain(args) { + + var entryFunction = Module['_main']; + + + args = args || []; + + var argc = args.length+1; + var argv = stackAlloc((argc + 1) * 4); + HEAP32[argv >> 2] = allocateUTF8OnStack(thisProgram); + for (var i = 1; i < argc; i++) { + HEAP32[(argv >> 2) + i] = allocateUTF8OnStack(args[i - 1]); + } + HEAP32[(argv >> 2) + argc] = 0; + + try { + + + var ret = entryFunction(argc, argv); + + + // In PROXY_TO_PTHREAD builds, we should never exit the runtime below, as execution is asynchronously handed + // off to a pthread. + // if we're not running an evented main loop, it's time to exit + exit(ret, /* implicit = */ true); + } + catch(e) { + if (e instanceof ExitStatus) { + // exit() throws this once it's done to make sure execution + // has been stopped completely + return; + } else if (e == 'unwind') { + // running an evented main loop, don't immediately exit + noExitRuntime = true; + return; + } else { + var toLog = e; + if (e && typeof e === 'object' && e.stack) { + toLog = [e, e.stack]; + } + err('exception thrown: ' + toLog); + quit_(1, e); + } + } finally { + calledMain = true; + } +} + + + + +/** @type {function(Array=)} */ +function run(args) { + args = args || arguments_; + + if (runDependencies > 0) { + return; + } + + + preRun(); + + if (runDependencies > 0) return; // a preRun added a dependency, run will be called later + + function doRun() { + // run may have just been called through dependencies being fulfilled just in this very frame, + // or while the async setStatus time below was happening + if (calledRun) return; + calledRun = true; + Module['calledRun'] = true; + + if (ABORT) return; + + initRuntime(); + + preMain(); + + if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); + + if (shouldRunNow) callMain(args); + + postRun(); + } + + if (Module['setStatus']) { + Module['setStatus']('Running...'); + setTimeout(function() { + setTimeout(function() { + Module['setStatus'](''); + }, 1); + doRun(); + }, 1); + } else + { + doRun(); + } +} +Module['run'] = run; + + +/** @param {boolean|number=} implicit */ +function exit(status, implicit) { + + // if this is just main exit-ing implicitly, and the status is 0, then we + // don't need to do anything here and can just leave. if the status is + // non-zero, though, then we need to report it. + // (we may have warned about this earlier, if a situation justifies doing so) + if (implicit && noExitRuntime && status === 0) { + return; + } + + if (noExitRuntime) { + } else { + + ABORT = true; + EXITSTATUS = status; + + exitRuntime(); + + if (Module['onExit']) Module['onExit'](status); + } + + quit_(status, new ExitStatus(status)); +} + +if (Module['preInit']) { + if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']]; + while (Module['preInit'].length > 0) { + Module['preInit'].pop()(); + } +} + +// shouldRunNow refers to calling main(), not run(). +var shouldRunNow = true; + +if (Module['noInitialRun']) shouldRunNow = false; + + + noExitRuntime = true; + +run(); + + + + + + +// {{MODULE_ADDITIONS}} + + +var BUFF_SIZE = 16384; +//var startRecordingButton = document.getElementById("startRecordingButton"); +//var stopRecordingButton = document.getElementById("stopRecordingButton"); +//var playButtonR = document.getElementById("playButtonR"); +//var playButtonD = document.getElementById("playButtonD"); +//var fileElem = document.getElementById('file-input'); +//var lRecordingMsg = document.getElementById('RecordingMessage'); +//var lProcessingMode = document.getElementById('ProcessingMode'); +//var lSampleRate = document.getElementById('SampleRate'); +//var lDataSize = document.getElementById('DataSize'); +//var lTimeIntervel = document.getElementById('TimeIntervel'); +//var lKbps = document.getElementById('Kbps'); +//var myBr = document.createElement('br'); + + +var fileContents = null; +var leftchannel = []; +var rightchannel = []; +var denoisedchannel = []; + +var recorder = null; +var recordingLength = 0; +var volume = null; +var mediaStream = null; +var sampleRate = 44100; +var sampleSize = 0; +var context = null; + +var blobIn = null; +var blobOut = null; +var wasm_processing_time = 0; +var total_wasm_processing_time = 0; + +function reset() { + fileContents = null; + leftchannel = []; + rightchannel = []; + denoisedchannel = []; + + recorder = null; + recordingLength = 0; + volume = null; + mediaStream = null; + sampleRate = 44100; + context = null; + + blobIn = null; + blobOut = null; +} + + +/* + fileElem.addEventListener('change', readSingleFile, false); + function readSingleFile(e) { + const file = e.target.files[0]; + + if (!file) { + return; + } + reset(); + + var reader = new FileReader(); + reader.onload = function(e) { + contents = e.target.result; + fileContents = contents; + + // Use WebAudio + var ac = new (AudioContext || webkitAudioContext)(); + ac.decodeAudioData(contents).then(function(buffer) { + audioBufferFromFile = buffer; + sampleRate = buffer.sampleRate; + recordingLength = buffer.length; + + leftchannel.push(audioBufferFromFile.getChannelData(0)); + sampleSize = audioBufferFromFile.getChannelData(0).length; + + //Input files are used for perf assessment. + denoisedchannel.push(wasm_denoise_stream_perf(audioBufferFromFile.getChannelData(0))); + // playF32Audio(buffer.getChannelData(0), 503784, 48000); + + + // console.log("Wasm Performance:"); + // console.log(); + // console.log("Processing Audio File: " + file.name); + // console.log("SampleRate: " + sampleRate); + // console.log("DataSize (bytes): " + sampleSize); + // console.log(); + // console.log("Time Intervel (ms): " + wasm_processing_time); + // console.log("Kbps: " + sampleSize / wasm_processing_time ); + + lProcessingMode.innerHTML = 'Processed Audio File: '+file.name+'
'; + lSampleRate.innerHTML = 'Sample Rate: '+sampleRate+'
'; + lDataSize.innerHTML = 'Data Size (bytes): '+sampleSize+'
'; + lTimeIntervel.innerHTML = 'Wasm Time Elapsed (ms): '+wasm_processing_time+'
'; + lKbps.innerHTML = 'Kbps: '+sampleSize/wasm_processing_time+'
'; + }) + }; + // reader.readAsBinaryString(file); + reader.readAsArrayBuffer(file); + + } + + +startRecordingButton.addEventListener("click", function () { + + reset(); + lRecordingMsg.innerHTML='Recording in progress..'; + + // Initialize recorder + navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; + navigator.getUserMedia( + { + audio: true + }, + function (e) { + console.log("user consent"); + + // creates the audio context + window.AudioContext = window.AudioContext || window.webkitAudioContext; + // context = new AudioContext({sampleRate: 48000}); + context = new AudioContext(); + + // creates an audio node from the microphone incoming stream + mediaStream = context.createMediaStreamSource(e); + + // onaudioprocess is triggered when bufferSize is full. Acceps power of two upto 16384. + var bufferSize = BUFF_SIZE; + + //currently limited to single channel audio. Sterio is doable fairly easily. + var numberOfInputChannels = 1; + var numberOfOutputChannels = 1; + + if (context.createScriptProcessor) { + recorder = context.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels); + } else { + recorder = context.createJavaScriptNode(bufferSize, numberOfInputChannels, numberOfOutputChannels); + } + + recorder.onaudioprocess = function (e) { + leftchannel.push(new Float32Array(e.inputBuffer.getChannelData(0))); + + var outbuffer = wasm_denoise_stream_perf(e.inputBuffer.getChannelData(0)); + + denoisedchannel.push(outbuffer); + recordingLength += bufferSize; + } + + // Recorder. Needs user permission. + mediaStream.connect(recorder); + recorder.connect(context.destination); + }, + function (e) { + console.error(e); + }); +}); + +stopRecordingButton.addEventListener("click", function () { + recorder.disconnect(context.destination); + mediaStream.disconnect(recorder); + lRecordingMsg.innerHTML=''; + + + lProcessingMode.innerHTML = 'Processed microphone stream:'+'
'; + lSampleRate.innerHTML = 'Sample Rate: '+sampleRate+'
'; + lDataSize.innerHTML = 'Data Size (bytes): '+recordingLength+'
'; + lTimeIntervel.innerHTML = 'Wasm Time Elapsed (ms): '+total_wasm_processing_time+'
'; + lKbps.innerHTML = 'Kbps: '+recordingLength/total_wasm_processing_time+'
'; + +}); + +playButtonR.addEventListener("click", function () { + if (leftchannel == null) { + return; + } + + var inAudioF32 = flattenArray(leftchannel, recordingLength); + playF32Audio(inAudioF32, recordingLength, sampleRate); +}); + +playButtonD.addEventListener("click", function () { + if (denoisedchannel == null) { + return; + } + + var outAudioF32 = flattenArray(denoisedchannel, recordingLength); + playF32Audio(outAudioF32, recordingLength, sampleRate); +}); + +*/ + +function flattenArray(channelBuffer, recordingLength) { + var result = new Float32Array(recordingLength); + var offset = 0; + for (var i = 0; i < channelBuffer.length; i++) { + var buffer = channelBuffer[i]; + result.set(buffer, offset); + offset += buffer.length; + } + return result; +} + +//Play raw f32Array audio using WebAudio +function playF32Audio(f32buffer, inSize, inSampleRate) { + + var audioCtx = new (window.AudioContext || window.webkitAudioContext)({sampleRate: inSampleRate}); + var myArrayBuffer = audioCtx.createBuffer(1, inSize, inSampleRate); + + myArrayBuffer.copyToChannel(f32buffer, 0,0); + + var source = audioCtx.createBufferSource(); + source.buffer = myArrayBuffer; + + source.connect(audioCtx.destination); + source.start(); +} + +//cwrap wasm api's for ease of use +// let wasm_rnnDenoiseMem = Module.cwrap('rnnDenoiseMem', 'number', ['number', 'number']); +let wasm_getsampleCount = Module.cwrap('getsampleCount', 'number'); +let wasm_getsampleRate = Module.cwrap('getsampleRate', 'number'); +let wasm_getResultSize = Module.cwrap('getResultSize', 'number', []); +let wasm_getResultPointer = Module.cwrap('getResultPointer', 'number', []); +let wasm_rnnDenoise_rawmem = Module.cwrap('rnnDenoise_rawmem', 'number', ['number', 'number', 'number', 'number']); +let wasm_rnnDenoise_rawmem_perf = Module.cwrap('rnnDenoise_rawmem_perf', 'number', ['number', 'number', 'number', 'number']); +let wasm_get_rnnDenoise_rawmem_time = Module.cwrap('get_rnnDenoise_rawmem_time', 'number', ['']); +let wasm_freeBuffer = Module.cwrap('freeBuffer', '', []); + + +//// +// WASM denoise wav files. will use wav library to decode. +// To enable define USE_WAV_MP3_LIBRARIES in rnnoise demo source and rebuild wasm modules +//// + +// function wasm_denoise_Arr(audioArrayBuffer) +// { +// var u8audiobuffer = new Uint8Array(audioArrayBuffer); +// let wasm_memp_in = Module._malloc(u8audiobuffer.length); +// let wasm_mem = new Uint8Array(wasmMemory.buffer, wasm_memp_in, u8audiobuffer.length); +// wasm_mem.set(u8audiobuffer); + +// //wasm call +// let x= wasm_rnnDenoiseMem(wasm_memp_in, u8audiobuffer.length); + +// recordingLength = getResultSize(); +// sampleRate = getsampleRate(); + +// let bProcessedArr = new Uint8Array(wasmMemory.buffer, x, u8audiobuffer.length); + +// var fProcessedArr = new Float32Array(getResultSize()); +// fProcessedArr = new Float32Array(wasmMemory.buffer, x, getsampleCount()); + +// //Test +// // playF32Audio(fProcessedArr, getResultSize(), getsampleRate()); + +// return fProcessedArr; +// } + +//WASM Denoise raw audio in f32array +function wasm_denoise_stream(f32buffer) { + + let wasm_memp_in = Module._malloc(f32buffer.length * 4 ); + let wasm_mem = new Float32Array(wasmMemory.buffer, wasm_memp_in, f32buffer.length); + wasm_mem.set(f32buffer); + + //wasm call + let x= wasm_rnnDenoise_rawmem(wasm_memp_in, sampleRate, 1, f32buffer.length); + + let fProcessedArr = new Float32Array(wasmMemory.buffer, x, f32buffer.length); + + //Test + // playF32Audio(f32buffer, fProcessedArr.length, sampleRate); + // playF32Audio(fProcessedArr, fProcessedArr.length, sampleRate); + + return fProcessedArr; +} + +//WASM Denoise raw audio in f32array +function wasm_denoise_stream_perf(f32buffer) { + + let wasm_memp_in = Module._malloc(f32buffer.length * 4); + let wasm_mem = new Float32Array(wasmMemory.buffer, wasm_memp_in, f32buffer.length); + wasm_mem.set(f32buffer); + + //wasm call + let t0 = performance.now(); + let x= wasm_rnnDenoise_rawmem(wasm_memp_in, sampleRate, 1, f32buffer.length); + let t1 = performance.now(); + wasm_processing_time = t1 - t0; + //lTimeIntervel.innerHTML='Buffer Processing Time: '+wasm_processing_time; + total_wasm_processing_time = total_wasm_processing_time + wasm_processing_time; + + // console.log( 'Buffer Processing Time: ' + wasm_processing_time ); + + + let fProcessedArr = new Float32Array(wasmMemory.buffer, x, f32buffer.length); + + return fProcessedArr; +} \ No newline at end of file diff --git a/audiomass-editor/src/rnn_denoise.wasm b/audiomass-editor/src/rnn_denoise.wasm new file mode 100644 index 0000000..e48145a Binary files /dev/null and b/audiomass-editor/src/rnn_denoise.wasm differ diff --git a/audiomass-editor/src/sp.html b/audiomass-editor/src/sp.html new file mode 100644 index 0000000..132cd73 --- /dev/null +++ b/audiomass-editor/src/sp.html @@ -0,0 +1,296 @@ + + + + + + AudioMass - Spectrum Analyzer + + + + + +

+ + DOCK INTERFACE + X + + + + + + \ No newline at end of file diff --git a/audiomass-editor/src/state.js b/audiomass-editor/src/state.js new file mode 100755 index 0000000..8203c35 --- /dev/null +++ b/audiomass-editor/src/state.js @@ -0,0 +1,117 @@ +(function ( PKAE ) { + 'use strict'; + + function PKState ( _depth, app ) { + if (!_depth) _depth = 1; + + var q = this; + + var _id = 1; + var _fireEvent = app.fireEvent; + var _listenFor = app.listenFor; + + var undo_state_list = []; + var redo_state_list = []; + + q.getLastUndoState = function () { + return (undo_state_list [ undo_state_list.length - 1]); + }; + + q.pushUndoState = function ( state ) { + if (!state) return (false); + + if (!state.id) state.id = ++_id; + if (undo_state_list.length >= _depth) undo_state_list.shift (); + + if (undo_state_list.length > 0) + { + if (undo_state_list[undo_state_list.length - 1].id !== state.id - 1) + undo_state_list = []; + } + if (redo_state_list.length > 0) + { + if (redo_state_list[0].id !== state.id + 1) + redo_state_list = []; + } + + undo_state_list.push ( state ); + + _fireEvent ( 'StatePush', undo_state_list.length ); + _fireEvent ( 'DidStateChange', undo_state_list, redo_state_list); + + return (true); + }; + + q.popUndoState = function () { + var last_state =undo_state_list.pop (); + + if (last_state) { + if (redo_state_list.length > 0) + { + if (redo_state_list[0].id !== last_state.id + 1) + redo_state_list = []; + } + + var temp = app.engine.wavesurfer.backend.buffer; + _fireEvent ( 'StateDidPop', last_state, 1 ); + + last_state.data = temp; + redo_state_list.unshift (last_state); + + _fireEvent ( 'DidStateChange', undo_state_list, redo_state_list); + } + + return (last_state); + }; + + q.shiftRedoState = function () { + var last_state = redo_state_list.shift (); + + if (last_state) { + if (undo_state_list.length > 0) + { + if (undo_state_list[undo_state_list.length - 1].id !== last_state.id - 1) + undo_state_list = []; + } + + var temp = app.engine.wavesurfer.backend.buffer; + _fireEvent ( 'StateDidPop', last_state, 0 ); + + last_state.data = temp; + undo_state_list.push (last_state); + + _fireEvent ( 'DidStateChange', undo_state_list, redo_state_list); + } + + return (last_state); + }; + + q.clearAllState = function () { + undo_state_list = []; + redo_state_list = []; + + _fireEvent ( 'StateClearAll' ); + _fireEvent ( 'DidStateChange', [], []); + }; + + _listenFor ('StateRequestPush', function ( _state ) { + q.pushUndoState ( _state ); + }); + _listenFor ('StateRequestUndo', function () { + q.popUndoState (); + }); + _listenFor ('StateRequestRedo', function () { + q.shiftRedoState (); + }); + _listenFor ('StateRequestClearAll', function () { + q.clearAllState (); + }); + _listenFor ('StateRequestLastState', function () { + _fireEvent ('StateDidLastState', q.getLastUndoState ()); + }); + // - + }; + + PKAE._deps.state = PKState; + +})( PKAudioEditor ); \ No newline at end of file diff --git a/audiomass-editor/src/sw.js b/audiomass-editor/src/sw.js new file mode 100644 index 0000000..ea7650d --- /dev/null +++ b/audiomass-editor/src/sw.js @@ -0,0 +1,59 @@ +const assets = [ + './manifest.json', + './ico.png', + './icon.png', + './index.html', + './main.css', + './dist/wavesurfer.js', + './dist/plugin/wavesurfer.regions.js', + './oneup.js', + './app.js', + './keys.js', + './contextmenu.js', + './ui-fx.js', + './ui.js', + './modal.js', + './state.js', + './engine.js', + './actions.js', + './drag.js', + './recorder.js', + './welcome.js', + './fx-pg-eq.js', + './fx-auto.js', + './local.js', + './id3.js', + './lzma.js', + './lame.js', + './fonts/icomoon.ttf', + './fonts/icomoon.woff', + './favicon.ico', + './eq.html', + './sp.html', + './test.mp3' + +]; + +self.addEventListener( 'install', async function () { + const cache = await caches.open( 'audiomass' ); + assets.forEach( function ( asset ) { + cache.add( asset ).catch( function () { + console.error( '[SW] Cound\'t cache:', asset ); + }); + }); +}); + +self.addEventListener( 'fetch', async function ( event ) { + const request = event.request; + event.respondWith( cacheFirst( request ) ); +}); + +async function cacheFirst( request ) { + const cachedResponse = await caches.match( request ); + if ( cachedResponse === undefined ) { + console.error( '[SW] Not cached:', request.url ); + return fetch( request ); + } + + return cachedResponse; +} \ No newline at end of file diff --git a/audiomass-editor/src/test.mp3 b/audiomass-editor/src/test.mp3 new file mode 100755 index 0000000..c83e20d Binary files /dev/null and b/audiomass-editor/src/test.mp3 differ diff --git a/audiomass-editor/src/ui-fx.js b/audiomass-editor/src/ui-fx.js new file mode 100755 index 0000000..b249399 --- /dev/null +++ b/audiomass-editor/src/ui-fx.js @@ -0,0 +1,1927 @@ +(function ( w, d, PKAE ) { + 'use strict'; + + + // STORING THE CUSTOM FX PRESETS IN LOCALSTORAGE + function PK_FX_PRESETS () { + var presets = {}; + + this.Set = function (filter_id, obj) { + var arr = presets[ filter_id ]; + + if (!arr) { + arr = []; + presets[ filter_id ] = arr; + } + + arr.push (obj); + localStorage.setItem ('pk_presetfx', JSON.stringify (presets)); + + return (arr); + } + + this.Save = function () { + localStorage.setItem ('pk_presetfx', JSON.stringify (presets)); + }; + + this.Get = function ( filter_id ) { + if (!filter_id) return (presets); + return (presets[ filter_id ]); + }; + + this.GetSingle = function ( filter_id, custom_id ) { + if (!filter_id) return (false); + if (!custom_id) return (false); + + var arr = presets[ filter_id ]; + var l = arr.length; + var found = null; + + while (l-- > 0) { + if (arr[l].id === custom_id) + { + found = arr[l]; + break; + } + } + + if (found) return (found); + return (false); + }; + + this.Del = function ( filter_id, custom_id ) { + if (!filter_id) return (presets); + + var arr = presets[ filter_id ]; + var l = arr.length; + var found = false; + + while (l-- > 0) { + if (arr[l].id === custom_id) + { + arr.splice (l, 1); + found = true; + break; + } + } + + if (found) + localStorage.setItem ('pk_presetfx', JSON.stringify (presets)); + + return (arr); + }; + + // loadCustomPresets + if (!w.localStorage) + { + this.Set = function(){}; + return ; + } + + var json = w.localStorage.getItem ('pk_presetfx'); + var tmp = null; + + if (!json) return ; + try { tmp = JSON.parse (json); } catch (e){} + + if (tmp) presets = tmp; + }; + + + + function PKUI_FX ( app ) { + var UI = app.ui; + + var curr_filter_ui = null; + var modal_name = 'modalfx'; + var modal_esc_key = modal_name + 'esc'; + + var custom_presets = new PK_FX_PRESETS (); + + + app.listenFor ('DidCloseFX_UI', function () { + curr_filter_ui = null; + }); + + app.listenFor ('DidOpenFX_UI', function ( modal ) { + curr_filter_ui = modal; + }); + + app.listenFor ('RequestFXUI_SELCUT', function () { + var eng = app.engine; + var wv = eng.wavesurfer; + var bk = wv.backend; + var rate = bk.buffer.sampleRate; + + var region = wv.regions.list[0]; + if (!region) return (false); + + app.fireEvent('RequestPause'); + + // mark the region as + region.element.style.background = 'red'; + + var reg = { + pos: { + start: (region.start * rate) >> 0, + end: (region.end * rate) >> 0 + }, + initpos: { + start: (region.start * rate) >> 0, + end: (region.end * rate) >> 0 + } + }; + + wv.backend.reg = reg; + + var update_reg = function( region ) { + reg.pos.start = (region.start * rate) >> 0; + reg.pos.end = (region.end * rate) >> 0; + + wv.drawBuffer (true); + }; + + wv.on ('region-updated', update_reg); + // -- now make sure we resize it if needed be + }); + + app.listenFor ('RequestFXUI_Gain', function () { + app.fireEvent ('RequestSelect', 1); + + var filter_id = 'gain'; + var auto = null; + + var getvalue = function ( q ) { + var value; + + if (auto) { + value = auto.GetValue (); + } else { + var input = q.el_body.getElementsByTagName('input')[0]; + value = [{val: input.value / 1}]; + } + + return (value); + }; + + var x = new PKAudioFXModal({ + id: filter_id, + title:'Apply Gain to selected range', + + presets:[ + {name:'Silence',val:0}, + {name:'-50%',val:0.5}, + {name:'-25%',val:0.75}, + {name:'+25%',val:1.25}, + {name:'+50%',val:1.5}, + {name:'+100%',val:2} + ], + custom_pres:custom_presets.Get (filter_id), + ondestroy: function ( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback (modal_esc_key); + }, + preview: function ( q ) { + var value = getvalue ( q ); + app.fireEvent ('RequestActionFX_PREVIEW_GAIN', value); + }, + buttons: [ + { + title:'Apply Gain', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var value = getvalue ( q ); + + if (value[0].val != 1.0) + app.fireEvent ('RequestActionFX_GAIN', value); + + q.Destroy (); + } + } + ], + body:'
' + + ''+ + '100%
' + + '
', + // 'Volume Graph
', + + setup:function( q ) { + var range = q.el_body.getElementsByTagName ('input')[0]; + var span = q.el_body.getElementsByTagName ('span')[0]; + var graph_btn = q.el_body.getElementsByTagName ('a')[0]; + + range.oninput = function() { + span.innerHTML = ((range.value * 100) >> 0) + '%'; + app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', [{val: range.value / 1}]); + }; + + //graph_btn.onclick = function () { + // auto = new PKAudioEditor._deps.FxAUT (app, q); + //}; + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet (modal_name); + app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + + q.Destroy (); + }, [27]); + } + }, app); + x.Show(); + }); + + app.listenFor ('RequestActionFXUI_Rate', function () { + app.fireEvent ('RequestSelect', 1); + + var filter_id = 'speed'; + + var x = new PKAudioFXModal({ + id: filter_id, + title:'Change Speed', + presets:[ + {name:'A lot slower',val:0.65}, + {name:'Slightly slower',val:0.85}, + {name:'Slightly faster',val:1.15}, + {name:'Blazing Fast',val:1.4} + ], + custom_pres:custom_presets.Get (filter_id), + ondestroy: function ( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback (modal_esc_key); + }, + preview: function ( q ) { + var input = q.el_body.getElementsByTagName('input')[0]; + var value = input.value.trim() / 1; + app.fireEvent ('RequestActionFX_PREVIEW_RATE', value); + }, + + buttons: [ + { + title:'Apply Rate', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var input = q.el_body.getElementsByTagName('input')[0]; + var value = input.value.trim() / 1; + + if (value != 1.0) + app.fireEvent ('RequestActionFX_RATE', value); + + q.Destroy (); + } + } + ], + body:'
' + + ''+ + '1.0
', + setup:function( q ) { + var range = q.el_body.getElementsByTagName('input')[0]; + var span = q.el_body.getElementsByTagName('span')[0]; + + range.oninput = function() { + span.innerHTML = range.value; + app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', range.value/1); + }; + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet (modal_name); + + app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + + q.Destroy (); + }, [27]); + } + }, app); + x.Show(); + }); + + app.listenFor ('RequestActionFXUI_Speed', function () { + app.fireEvent ('RequestSelect', 1); + + var filter_id = 'speed'; + + var x = new PKAudioFXModal({ + id: filter_id, + title:'Change Speed', + presets:[ + {name:'-1/4',val:0.25}, + {name:'-1/2',val:0.5}, + {name:'Slightly slower',val:0.85}, + {name:'Slightly faster',val:1.1}, + {name:'+1/4',val:1.25}, + {name:'+1/2',val:1.5} + ], + custom_pres:custom_presets.Get (filter_id), + ondestroy: function ( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback (modal_esc_key); + }, + preview: function ( q ) { + var input = q.el_body.getElementsByTagName('input')[0]; + var value = input.value.trim() / 1; + app.fireEvent ('RequestActionFX_PREVIEW_SPEED', value); + }, + + buttons: [ + { + title:'Apply Rate', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var input = q.el_body.getElementsByTagName('input')[0]; + var value = input.value.trim() / 1; + + if (value != 1.0) + app.fireEvent ('RequestActionFX_SPEED', value); + + q.Destroy (); + } + } + ], + body:'
' + + ''+ + '1.0
', + setup:function( q ) { + var range = q.el_body.getElementsByTagName('input')[0]; + var span = q.el_body.getElementsByTagName('span')[0]; + + range.oninput = function() { + span.innerHTML = range.value; + app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', range.value/1); + }; + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet (modal_name); + + app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + + q.Destroy (); + }, [27]); + } + }, app); + x.Show(); + }); + + + app.listenFor ('RequestActionFXUI_Flip', function () { + if (!PKAudioEditor.engine.is_ready) return ; + + app.fireEvent ( 'RequestRegionClear'); + app.fireEvent ('RequestSelect', 1); + + var filter_id = 'flip'; + var mode = 0; + + var x = new PKAudioFXModal({ + id: filter_id, + title:'Channel Info', + ondestroy: function ( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback (modal_esc_key); + }, + buttons: [ + { + title:'Apply Changes', + clss:'pk_modal_a_accpt', + callback: function( q ) { + if (mode === 1) + { + // check if we are doing force mono, or force flip + var mono = q.el_body.getElementsByClassName('pk_c_mm')[0]; + var flip = q.el_body.getElementsByClassName('pk_c_fl')[0]; + + if (mono.checked) + { + var chans = q.el_body.getElementsByClassName('pk_c_c'); + // check which channel we pick + + if (chans[0].checked) { + app.fireEvent ('RequestActionFX_Flip', 'mono', 0); + } + else if (chans[1].checked) { + app.fireEvent ('RequestActionFX_Flip', 'mono', 1); + } + } + else if (flip.checked) { + app.fireEvent ('RequestActionFX_Flip', 'flip'); + } + } + + else if (mode === 2) + { + var stereo = q.el_body.getElementsByClassName('pk_c_ms')[0]; + if (stereo.checked) { + app.fireEvent ('RequestActionFX_Flip', 'stereo'); + } + } + + q.Destroy (); + } + } + ], + body:'' + + + '', + setup:function( q ) { + var main = null; + var num = PKAudioEditor.engine.wavesurfer.backend.buffer.numberOfChannels; + if (num === 2) + { + mode = 1; + main = q.el_body.getElementsByClassName('pk_mm')[0]; + + var mono = main.getElementsByClassName('pk_c_mm')[0]; + var flip = main.getElementsByClassName('pk_c_fl')[0]; + var chans = main.getElementsByClassName('pk_c_c'); + var tmp = main.getElementsByClassName('pk_dis'); + var lbls = [tmp[0], tmp[1]]; + + mono.onchange = function( e ) { + if (mono.checked) { + flip.checked = false; + chans[0].checked = true; + lbls[0].className = ''; + lbls[1].className = ''; + } + else { + chans[0].checked = false; + chans[1].checked = false; + lbls[0].className = 'pk_dis'; + lbls[1].className = 'pk_dis'; + } + }; + + flip.onchange = function( e ) { + if (flip.checked) { + mono.checked = false; + mono.onchange (); + } + }; + + } + else + { + mode = 2; + main = q.el_body.getElementsByClassName('pk_ms')[0]; + } + + main.style.display = 'block'; + + // -- + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet (modal_name); + app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + q.Destroy (); + }, [27]); + } + }, app); + x.Show(); + }); + + + + app.listenFor ('RequestFXUI_Silence', function () { + var x = new PKSimpleModal({ + title: 'Insert Silence', + ondestroy: function( q ) { + UI.InteractionHandler.on = false; + UI.KeyHandler.removeCallback ('modalTemp'); + }, + buttons:[ + { + title:'Insert Silence', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var input = q.el_body.getElementsByClassName('pk_horiz')[0]; + var value = input.value.trim() / 1; + + var radios = q.el_body.getElementsByClassName('pk_check'); + var offset = 0; + + if (radios[1].checked) + offset = PKAudioEditor.engine.wavesurfer.getCurrentTime().toFixed(3)/1; + + if (value > 0.001) + UI.fireEvent ('RequestActionSilence', offset, value); + q.Destroy (); + } + } + ], + body:'
'+ + '
' + + ''+ + '
'+ + '
'+ + ''+ + '5s
', + setup:function( q ) { + var cursor_pos_el = q.el_body.getElementsByClassName('pkcdpk')[0]; + cursor_pos_el.innerHTML = PKAudioEditor.engine.wavesurfer.getCurrentTime().toFixed(2) + 's'; + + var range = q.el_body.getElementsByClassName('pk_horiz')[0]; + var span = q.el_body.getElementsByClassName('pk_val')[0]; + + range.oninput = function() { + span.innerHTML = (range.value/1).toFixed (2) + 's'; + }; + + UI.fireEvent ('RequestPause'); + UI.InteractionHandler.checkAndSet ('modal'); + UI.KeyHandler.addCallback ('modalTemp', function ( e ) { + q.Destroy (); + }, [27]); + } + }); + x.Show(); + }); + + + app.listenFor ('RequestActionFXUI_Compressor', function () { + app.fireEvent ('RequestSelect', 1); + + var filter_id = 'compressor'; + var auto = null; + var getvalue = function ( q ) { + var ret; + var value = []; + + if (auto) { + value = auto.GetValue (); + } else { + var inputs = q.el_body.getElementsByTagName('input'); + value[0] = {val:inputs[0].value / 1}; + value[1] = {val:inputs[1].value / 1}; + value[2] = {val:inputs[2].value / 1}; + value[3] = {val:inputs[3].value / 1}; + value[4] = {val:inputs[4].value / 1}; + } + + ret = { + threshold: value[0], + knee: value[1], + ratio: value[2], + attack: value[3], + release: value[4] + }; + + return (ret); + }; + + var x = new PKAudioFXModal({ + id : filter_id, + title : 'Apply Compression to selected range', + clss : 'pk_bigger', + ondestroy: function ( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback (modal_esc_key); + }, + presets:[ + {name:'Classic',val:'-40,5,7,0.002,0.1'}, + {name:'Light',val:'-6,2,2.5,0.002,0.05'}, + {name:'Dashed Distortion',val:'-45,26,2.05,0.233,0.0'}, + {name:'Chaotic Distortion',val:'-60,14,11.07,0.036,0.00'} + ], + custom_pres:custom_presets.Get (filter_id), + preview: function ( q ) { + var inputs = q.el_body.getElementsByTagName('input'); + var val = getvalue (q); + app.fireEvent ('RequestActionFX_PREVIEW_COMPRESSOR', val); + }, + + buttons: [ + { + title:'Apply', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var inputs = q.el_body.getElementsByTagName('input'); + var val = getvalue ( q ); + + app.fireEvent ('RequestActionFX_Compressor', val); + + q.Destroy (); + } + } + ], + body:'
' + + ''+ + '-24.0
'+ + + '
' + + ''+ + '30.0
'+ + + '
' + + ''+ + '12.0
'+ + + '
' + + ''+ + '0.003
'+ + + '
' + + ''+ + '0.25
', + //'Volume Graph
', + setup:function( q ) { + var inputs = q.el_body.getElementsByTagName ('input'); + for (var i = 0; i < inputs.length; ++i) + { + inputs[i].oninput = function () { + var span = this.parentNode.getElementsByTagName ('span')[0]; + span.innerHTML = (this.value/1).toFixed (3); + + updateFilter (); + }; + } + + //var graph_btn = q.el_body.getElementsByTagName ('a')[0]; + //graph_btn.onclick = function () { + // auto = new PKAudioEditor._deps.FxAUT (PKAudioEditor, q); + //}; + + function updateFilter() { + var val = getvalue ( q ); + app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', val); + } + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet (modal_name); + app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + q.Destroy (); + }, [27]); + // --- + } + }, app); + x.Show(); + }); + + + app.listenFor ('RequestActionFXUI_Normalize', function () { + app.fireEvent ('RequestSelect', 1); + + var x = new PKSimpleModal({ + title: 'Normalize', + ondestroy: function( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback ('modalTemp'); + }, + buttons:[ + { + title:'Normalize Audio', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var input = q.el_body.getElementsByClassName('pk_horiz')[0]; + var value = (input.value / 1); + + var toggle = q.el_body.getElementsByClassName('pk_check')[0].checked; + app.fireEvent ('RequestActionFX_Normalize', [toggle, value]); + q.Destroy (); + } + } + ], + body:'
'+ + ''+ + '
' + + '
'+ + ''+ + '100%
', + setup:function( q ) { + var range = q.el_body.getElementsByClassName('pk_horiz')[0]; + var span = q.el_body.getElementsByClassName('pk_val')[0]; + + range.oninput = function() { + span.innerHTML = (((range.value/1)*100) >> 0) + '%'; + }; + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet ('modal'); + app.ui.KeyHandler.addCallback ('modalTemp', function ( e ) { + q.Destroy (); + }, [27]); + } + });x.Show(); + }); + + + app.listenFor ('RequestActionFXUI_ParaGraphicEQ', function () { + PKAudioEditor._deps.FxEQ (app, custom_presets); + }); + + app.listenFor ('RequestActionTempo', function () { + PKAudioEditor._deps.FxTMP (app); + }); + + app.listenFor ('RequestActionNewRec', function () { + PKAudioEditor._deps.FxREC (app); + }); + + //app.listenFor ('RequestActionAUTO', function ( filter ) { + // PKAudioEditor._deps.FxAUT (app, filter); + //}); + + app.listenFor ('RequestActionFXUI_GraphicEQ', function ( num_of_bands ) { + app.fireEvent ('RequestSelect', 1); + + var filter_id = 'graph_eq'; + var auto = null; + var getvalue = function ( ranges ) { + var val = {}; + + if (auto) { + val = auto.GetValue (); + } else { + val = []; + var len = ranges.length; + for (var i = 0; i < len; ++i) + { + var range = ranges [ i ]; + val.push ({ + 'type' : range.getAttribute ('data-type'), + 'freq' : range.getAttribute ('data-freq')/1, + 'val' : range.value / 1, + 'q' : band_q + }); + } + } + + return (val); + }; + + var bands_str = '
0 db'+ + ''+ + '< 32hz
'+ + '
0 db'+ + ''+ + '64hz
'+ + '
0 db'+ + ''+ + '125hz
'+ + '
0 db'+ + ''+ + '250hz
'+ + '
0 db'+ + ''+ + '500hz
'+ + '
0 db'+ + ''+ + '1000hz
'+ + '
0 db'+ + ''+ + '2000hz
'+ + '
0 db'+ + ''+ + '4000hz
'+ + '
0 db'+ + ''+ + '8000hz
'+ + '
0 db'+ + ''+ + ' >16000hz
'; + var presets = [ + {name:'Reset', val:'0,0,0,0,0,0,0,0,0,0'}, + {name:'Old Radio', val:'-25,-22,-20,-18,-9,0,8,10,-8,-25'}, + {name:'Lo Fi', val:'-18,-12,0,2,0,4,4,-1,-6,-8'} + ]; + var band_q = 4.6; + + if (num_of_bands === 20) + { + filter_id += '_2'; + presets = null; // maybe add presets? + band_q = 10.2; + bands_str = '
0 db'+ + ''+ + '< 31hz
'+ + '
0 db'+ + ''+ + '44hz
'+ + '
0 db'+ + ''+ + '63hz
'+ + '
0 db'+ + ''+ + '88hz
'+ + '
0 db'+ + ''+ + '125hz
'+ + '
0 db'+ + ''+ + '180hz
'+ + '
0 db'+ + ''+ + '250hz
'+ + '
0 db'+ + ''+ + '335hz
'+ + '
0 db'+ + ''+ + '500hz
'+ + '
0 db'+ + ''+ + '710hz
'+ + '
0 db'+ + ''+ + '1khz
'+ + '
0 db'+ + ''+ + '1.4khz
'+ + '
0 db'+ + ''+ + '2khz
'+ + '
0 db'+ + ''+ + '2.8khz
'+ + '
0 db'+ + ''+ + '4khz
'+ + '
0 db'+ + ''+ + '5.6khz
'+ + '
0 db'+ + ''+ + '8khz
'+ + '
0 db'+ + ''+ + '11.3khz
'+ + '
0 db'+ + ''+ + '16k
'+ + '
0 db'+ + ''+ + ' >22khz
'; + } + + var x = new PKAudioFXModal({ + id: filter_id, + title:'Graphic EQ', + clss: num_of_bands === 20 ? 'pk_dens' : '', + custom_pres:custom_presets.Get (filter_id), + ondestroy: function ( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback (modal_esc_key); + }, + preview: function ( q ) { + var ranges = q.el_body.getElementsByTagName('input'); + var len = ranges.length; + + app.fireEvent ('RequestActionFX_PREVIEW_PARAMEQ', getvalue (ranges)); + }, + + buttons: [ + { + title:'Apply EQ', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var ranges = q.el_body.getElementsByTagName('input'); + app.fireEvent ('RequestActionFX_PARAMEQ', getvalue (ranges)); + + q.Destroy (); + } + } + ], + presets:presets, + body:'
' + + bands_str+ + '
', + //'Volume Graph', + setup:function( q ) { + var ranges = q.el_body.getElementsByTagName('input'); + var len = ranges.length; + + //var graph_btn = q.el_body.getElementsByTagName ('a')[0]; + //graph_btn.onclick = function () { + // auto = new PKAudioEditor._deps.FxAUT (PKAudioEditor, q, function ( obj, range ) { + // obj.type = range.getAttribute ('data-type'); + // obj.freq = range.getAttribute ('data-freq')/1; + // obj.q = band_q; + // }); + //}; + + for (var i = 0; i < len; ++i) { + var range = ranges[i]; + + range.oninput = function() { + var span = this.parentNode.getElementsByTagName('span')[0]; + span.innerHTML = ((this.value) >> 0) + ' db'; + app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', getvalue (ranges)); + }; + } + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet (modal_name); + app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + q.Destroy (); + }, [27]); + } + }, app); + x.Show(); + }); + + + app.listenFor ('RequestActionFXUI_HardLimiter', function () { + + app.fireEvent ('RequestSelect', 1); + + var x = new PKAudioFXModal({ + title: 'Hard Limiting', + ondestroy: function( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback ('modalTemp'); + }, + buttons:[ + { + title:'Hard Limiting', + clss:'pk_modal_a_accpt', + callback: function( q ) { + app.fireEvent ('RequestActionFX_HardLimit', q.updateFilter (q)); + q.Destroy (); + } + } + ], + preview: function ( q ) { + app.fireEvent ('RequestActionFX_PREVIEW_HardLimit', q.updateFilter ( q )); + }, + body: + '
'+ + '
' + + + '
'+ + ''+ + '99%
'+ + + '
'+ + ''+ + 'Ratio 0%
'+ + + '
'+ + ''+ + '10 ms
', + updateFilter : function ( q ) { + var val = [q.el_body.getElementsByClassName('pk_check')[0].checked]; + var ranges = q.el_body.getElementsByClassName('pk_horiz'); + + for (var i = 0; i < ranges.length; ++i) + { + var range = ranges [ i ]; + val.push (range.value / 1); + } + return (val); + }, + setup:function( q ) { + var ranges = q.el_body.getElementsByClassName('pk_horiz'); + + ranges[0].oninput = function() { + var span = this.parentNode.getElementsByTagName('span')[0]; + span.innerHTML = (((this.value/1)*100) >> 0) + '%'; + app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', q.updateFilter (q)); + }; + ranges[1].oninput = function() { + var span = this.parentNode.getElementsByTagName('span')[0]; + span.innerHTML = 'Ratio ' + (((this.value/1)*100) >> 0) + '%'; + app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', q.updateFilter (q)); + }; + ranges[2].oninput = function() { + var span = this.parentNode.getElementsByTagName('span')[0]; + span.innerHTML = (this.value/1) + 'ms'; + app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', q.updateFilter (q)); + }; + + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet ('modal'); + app.ui.KeyHandler.addCallback ('modalTemp', function ( e ) { + q.Destroy (); + }, [27]); + } + }, app);x.Show(); + }); + + + app.listenFor ('RequestActionFXUI_Delay', function () { + app.fireEvent ('RequestSelect', 1); + + var filter_id = 'delay'; + var auto = null; + var getvalue = function ( q ) { + var ret; + var value = []; + + if (auto) { + value = auto.GetValue (); + } else { + var inputs = q.el_body.getElementsByTagName('input'); + value[0] = {val:inputs[0].value / 1}; + value[1] = {val:inputs[1].value / 1}; + value[2] = {val:inputs[2].value / 1}; + } + + ret = { + delay: value[0], + feedback: value[1], + mix: value[2] + }; + + return (ret); + }; + + var x = new PKAudioFXModal({ + id : filter_id, + title : 'Apply Delay to selected range', + clss : 'pk_bigger', + ondestroy: function ( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback (modal_esc_key); + }, + presets:[ + {name:'Classic',val:'0.3,0.4,0.4'}, + {name:'Spacey',val:'3.0,0.6,0.3'} + ], + custom_pres:custom_presets.Get (filter_id), + preview: function ( q ) { + var val = getvalue (q); + + app.fireEvent ('RequestActionFX_PREVIEW_DELAY', val); + }, + + buttons: [ + { + title:'Apply', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var val = getvalue (q); + + app.fireEvent ('RequestActionFX_DELAY', val); + + q.Destroy (); + } + } + ], + body:'
' + + ''+ + '0.28
'+ + + '
' + + ''+ + '0.5
'+ + + '
' + + ''+ + '0.4
', + //'Volume Graph', + setup:function( q ) { + var inputs = q.el_body.getElementsByTagName ('input'); + for (var i = 0; i < inputs.length; ++i) + { + inputs[i].oninput = function () { + var span = this.parentNode.getElementsByTagName ('span')[0]; + span.innerHTML = (this.value/1).toFixed (3); + + updateFilter (); + }; + } + + //var graph_btn = q.el_body.getElementsByTagName ('a')[0]; + //graph_btn.onclick = function () { + // auto = new PKAudioEditor._deps.FxAUT (app, q); + //}; + + function updateFilter() { + var val = getvalue (q); + app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', val); + } + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet (modal_name); + app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + q.Destroy (); + }, [27]); + // --- + } + }, app); + x.Show(); + }); + + + app.listenFor ('RequestActionFXUI_Distortion', function () { + app.fireEvent ('RequestSelect', 1); + + var filter_id = 'dist'; + var auto = null; + var getvalue = function ( q ) { + var value; + + if (auto) { + value = auto.GetValue (); + } else { + var input = q.el_body.getElementsByTagName('input')[0]; + value = [{val: input.value / 1}]; + } + + return (value); + }; + + var x = new PKAudioFXModal({ + id : filter_id, + title : 'Apply Distortion to selected range', + clss : 'pk_bigger', + ondestroy: function ( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback (modal_esc_key); + }, + preview: function ( q ) { + var val = getvalue (q); + app.fireEvent ('RequestActionFX_PREVIEW_DISTORT', val); + }, + + buttons: [ + { + title:'Apply', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var val = getvalue (q); + app.fireEvent ('RequestActionFX_DISTORT', val); + + q.Destroy (); + } + } + ], + body:'
' + + ''+ + '0.5
', + // 'Volume Graph', + + setup:function( q ) { + var inputs = q.el_body.getElementsByTagName ('input'); + for (var i = 0; i < inputs.length; ++i) + { + inputs[i].oninput = function () { + var span = this.parentNode.getElementsByTagName ('span')[0]; + span.innerHTML = (this.value/1).toFixed (2); + + updateFilter (); + }; + } + + //var graph_btn = q.el_body.getElementsByTagName ('a')[0]; + //graph_btn.onclick = function () { + // auto = new PKAudioEditor._deps.FxAUT (app, q); + //}; + + function updateFilter() { + var val = getvalue (q); + app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', val); + } + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet (modal_name); + app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + q.Destroy (); + }, [27]); + // --- + } + }, app); + x.Show(); + }); + + + app.listenFor ('RequestActionFXUI_Reverb', function () { + app.fireEvent ('RequestSelect', 1); + + var filter_id = 'reverb'; + + var x = new PKAudioFXModal({ + id : filter_id, + title : 'Apply Reverb to selected range', + clss : 'pk_bigger', + ondestroy: function ( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback (modal_esc_key); + }, + presets:[ + {name:'Classic',val:'0.3,0.4,0.4'}, + {name:'Spacey',val:'3.0,0.6,0.3'} + ], + custom_pres:custom_presets.Get (filter_id), + preview: function ( q ) { + var inputs = q.el_body.getElementsByTagName('input'); + var val = { + time: inputs[0].value/1, + decay: inputs[1].value/1, + mix: inputs[2].value/1 + }; + app.fireEvent ('RequestActionFX_PREVIEW_REVERB', val); + }, + + buttons: [ + { + title:'Apply', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var inputs = q.el_body.getElementsByTagName('input'); + var val = { + time: inputs[0].value/1, + decay: inputs[1].value/1, + mix: inputs[2].value/1 + }; + + app.fireEvent ('RequestActionFX_REVERB', val); + + q.Destroy (); + } + } + ], + body:'
' + + ''+ + '0.3
'+ + + '
' + + ''+ + '0.05
'+ + + '
' + + ''+ + '0.6
', + setup:function( q ) { + var inputs = q.el_body.getElementsByTagName ('input'); + for (var i = 0; i < inputs.length; ++i) + { + inputs[i].oninput = function () { + var span = this.parentNode.getElementsByTagName ('span')[0]; + span.innerHTML = (this.value/1).toFixed (3); + + updateFilter (); + }; + } + + function updateFilter() { + var inputs = q.el_body.getElementsByTagName('input'); + var val = { + time: inputs[0].value/1, + decay: inputs[1].value/1, + mix: inputs[2].value/1 + }; + + app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', val); + } + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet (modal_name); + app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) { + if (!app.ui.InteractionHandler.check (modal_name)) return ; + q.Destroy (); + }, [27]); + // --- + } + }, app); + x.Show(); + }); + + // ----- + + var current_tags = null; + app.listenFor ('RequestActionID3', function (flag, new_tags) { + if (flag) { + current_tags = new_tags; + return ; + } + + var modal_id = '_id3'; + + var render_tags = function ( el, tags ) { + var str = '
'; + + str += '
Artist' + (tags.artist || '-') + '
'; + str += '
Title' + (tags.title || '-') + '
'; + str += '
Album' + (tags.album || '-') + '
'; + str += '
Year' + (tags.year || '-') + '
'; + str += '
Genre' + (tags.genre || '-') + '
'; + str += '
Comment' + ((tags.comment||{}).text || '-') + '
'; + str += '
Track' + (tags.track || '-') + '
'; + str += '
Lyrics' + ((tags.lyrics||{}).lyrics || '-') + '
'; + + if ('picture' in tags) + { + var image = tags.picture; + var base64str = ''; + for (var i = 0; i < image.data.length; ++i) { + base64str += String.fromCharCode (image.data[i]); + } + + str += '
Cover' + + '
'; + } + + el.innerHTML = str + '
'; + }; + + new PKSimpleModal({ + title:'ID3 Metatags Explorer', + + ondestroy: function( q ) { + app.ui.InteractionHandler.forceUnset (modal_id); + app.ui.KeyHandler.removeCallback (modal_id + 'esc'); + }, + + buttons:[ + ], + body:''+ + '
Choose file to view audio metatags!
', + setup:function( q ) { + var input = q.el_body.getElementsByTagName ('input')[0]; + var txt_el = q.el_body.getElementsByClassName ('pk_ttx')[0]; + + input.onchange = function ( e ) { + var reader = new FileReader(); + + reader.onload = function() { + var tags = PKAudioEditor.engine.ID3 (this.result); + + if (!tags) { + txt_el.innerHTML = '
No audio metadata found...
'; + } else { + render_tags (txt_el, tags); + } + }; + + reader.readAsArrayBuffer(this.files[0]); + }; + + if (current_tags) { + render_tags (txt_el, current_tags); + } + + app.ui.InteractionHandler.forceSet (modal_id); + app.ui.KeyHandler.addCallback (modal_id + 'esc', function ( e ) { + if (!app.ui.InteractionHandler.check (modal_id)) return ; + q.Destroy (); + }, [27]); + } + }).Show(); + + }); + + + // ---- save presets + app.listenFor ('RequestSavePreset', function () { + if (!curr_filter_ui) return ; + + var el = curr_filter_ui.el_body; + if (!el) return ; + + var escapeHtml = function (text) { + var map = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + + return text.replace(/[&<>"']/g, function(m) { return map[m]; }); + }; + + // check if the preset is custom + var is_new = true; + var custom_id = null; + var el_presets = curr_filter_ui.el_presets; + var sel_opt = el_presets.options[el_presets.selectedIndex]; + + var inputs = el.querySelectorAll('select, input'); + var preset_obj = { + target:curr_filter_ui.id, + name:'My Preset', + id:curr_filter_ui.id + '_' + ((Math.random() * 99) >> 0), + date:Date.now(), + val:'' + }; + + if (sel_opt && sel_opt.getAttribute('data-custom')) + { + is_new = false; + custom_id = sel_opt.getAttribute('data-custom'); + } + + // ---------- + for (var i = 0; i < inputs.length; ++i) + { + if (inputs[i].type === 'checkbox') { + preset_obj.val += (inputs[i].checked ? '1' : '0') + ','; + } + else { + preset_obj.val += inputs[i].value + ','; + } + } + + if (preset_obj.val.length > 0) + { + preset_obj.val = preset_obj.val.substring(0, preset_obj.val.length - 1); + + // open ui for setting preset name + var modal_id = '_ctPr'; + var default_txt = ''; + + var btn_delete = {}; + var btn_update = {}; + var custom_obj = null; + + if (!is_new) + { + custom_obj = custom_presets.GetSingle (preset_obj.target, custom_id); + default_txt = 'value="' + custom_obj.name + '"'; + + btn_delete = { + title:'Delete', + clss:'pk_modal_a_red', + callback: function( q ) { + + OneUp ('Successfully deleted preset!', 1400); + + var custom = custom_presets.Del (preset_obj.target, custom_id); + app.fireEvent ('DidSetPresets', preset_obj.target, custom); + + q.Destroy (); + // - + } + }; + + btn_update = { + title:'Update', + callback: function( q ) { + + if (custom_obj) + { + var input = q.el_body.getElementsByTagName ('input')[0]; + var value = input.value.trim (); + + value = escapeHtml (value); + + if (value.length > 0) + { + OneUp ('Successfully updated preset!', 1400); + + // add preset to localStorage + custom_obj.name = value; + custom_obj.val = preset_obj.val; + + custom_presets.Save (); + + var arr = custom_presets.Get (preset_obj.target); + app.fireEvent ('DidSetPresets', preset_obj.target, arr); + + q.Destroy (); + } + else + { + OneUp ('Name is too short...', 1200); + } + } + // - + } + }; + } + + var title = 'Save Custom Preset for filter "' + curr_filter_ui.id + '"'; + if (!is_new) { + var cname = custom_obj.name; + title = 'Edit Custom Preset "' + cname + '", for filter "' + curr_filter_ui.id + '"'; + } + + new PKSimpleModal({ + title:title, + + ondestroy: function( q ) { + app.ui.InteractionHandler.forceUnset (modal_id); + + app.ui.KeyHandler.removeCallback (modal_id + 'esc'); + app.ui.KeyHandler.removeCallback (modal_id + 'ent'); + }, + + buttons:[ + { + title: is_new ? 'Save' : 'Save As New', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var input = q.el_body.getElementsByTagName ('input')[0]; + var value = input.value.trim (); + + value = escapeHtml (value); + + if (value.length > 0) + { + OneUp ('Successfully saved preset!', 1400); + + // add preset to localStorage + preset_obj.name = value; + + var custom = custom_presets.Set (preset_obj.target, preset_obj); + + app.fireEvent ('DidSetPresets', preset_obj.target, custom); + app.fireEvent ('RequestSetPresetActive', preset_obj.target, preset_obj.id); + + q.Destroy (); + } + else + { + OneUp ('Name is too short...', 1200); + } + // - + } + }, + + btn_update, + btn_delete + ], + body:'' + + '', + setup:function( q ) { + // app.fireEvent ('RequestPause'); + + app.ui.InteractionHandler.forceSet (modal_id); + + app.ui.KeyHandler.addCallback (modal_id + 'esc', function ( e ) { + if (!app.ui.InteractionHandler.check (modal_id)) return ; + + q.Destroy (); + }, [27]); + + app.ui.KeyHandler.addCallback (modal_id + 'en', function ( e ) { + if (!app.ui.InteractionHandler.check (modal_id)) return ; + + q.els.bottom[0].click (); + }, [13]); + + setTimeout(function() { + if (q.el) { + var inp = q.el.getElementsByTagName('input')[0]; + inp.focus (); + + if (inp.value.length > 0) { + inp.selectionStart = inp.selectionEnd = inp.value.length; + } + } + },20); + } + }).Show(); + // --- + } + + // document.querySelector('.pk_modal_main').getElementsByTagName('input')[0].value + }); + + + + + + + + + + // ---- windows ---- + + var eq_win = {}; + + app.listenFor ('WillUnload', function () { + var cur; + + for (var k in eq_win) { + cur = eq_win[k]; + if (cur && !cur.type) { + cur.destroy && cur.destroy (); + } + } + + eq_win = {}; + }); + + app.listenFor ('RequestDragI', function ( url ) { + if (app.isMobile) { + alert ('unsupported on mobile'); + return ; + } + + var cur_win = eq_win[url]; + + if (!cur_win || !cur_win.el) return ; + + cur_win.el.style.pointerEvents = 'none'; + cur_win.el.style.zIndex = '9'; + + cur_win.win.document.body.classList.add ('c'); + + var el_back = document.createElement ('div'); + el_back.className = 'pk_modal_back'; + document.body.appendChild (el_back); + + var is_drag = true; + var x = 0; + var y = 0; + var moved = 2; + + var top = parseInt (cur_win.el.style.top) || 0; + var left = parseInt (cur_win.el.style.left) || 0; + + app.ui.InteractionHandler.on = true; + + setTimeout (function() { + if (cur_win && cur_win.el) + { + cur_win.el.style.display = 'none'; + setTimeout(function() { + cur_win.el.style.display = 'block'; + },0); + el_back.focus (); + } + }, 60); + + el_back.onmousemove = function ( e ) { + if (!is_drag) return ; + + if (x === 0 && y === 0) + { + x = e.pageX; + y = e.pageY; + + return ; + } + + var dist_x = e.pageX - x; + var dist_y = e.pageY - y; + + top += dist_y; + left += dist_x; + + cur_win.el.style.top = top + 'px'; + cur_win.el.style.left = left + 'px'; + + x = e.pageX; + y = e.pageY; + + --moved; + }; + + el_back.onmouseup = function ( e ) { + is_drag = false; + + cur_win.win.document.body.classList.remove ('c'); + cur_win.el.style.pointerEvents = ''; + cur_win.el.style.zIndex = '7'; + + app.ui.InteractionHandler.on = false; + + document.body.removeChild (el_back); + + if (e.type === 'mouseup') + { + if (moved > 0) + { + cur_win.el.style.top = '0px'; + + var ch = app.ui.BarBtm.el.childNodes; + + var lw = 0; + for (var ji = 0; ji < ch.length; ++ji) { + if (cur_win.el === ch[ji]) break; + lw += ch[ji].clientWidth + 18; + } + + cur_win.el.style.left = lw + 'px'; + // ---- + } + // check if we didn't move - in that return + } + + el_back.onmousemove = null; + el_back.onmouseleave = null; + el_back.onmouseup = null; + el_back = null; + }; + + el_back.onmouseleave = function ( e ) { + el_back.onmouseup ( e ); + app.fireEvent ('RequestShowFreqAn', url, [ [(window.screenLeft + e.pageX)||0, (window.screenTop + e.pageY)||0], 0]); + }; + }); + + app.listenFor ('RequestShowFreqAn', function ( url, args_arr ) { + + if (app.isMobile) { + alert ('Currently unsupported on mobile'); + return ; + } + + var toggle = args_arr[ 0 ]; + var type = args_arr[ 1 ]; + var title = 'Frequency Analysis'; + var curr_win = eq_win[ url ]; + + if (url === 'sp') title = 'Spectrum Analysis'; + + var toggled = false; + if (curr_win && toggle) + { + var ext = false; + if (curr_win.type === type) ext = true; + + curr_win.destroy (); + curr_win = null; + + eq_win[url] = null; + + if (ext) return ; + toggled = true; + } + + var freq_cb = function (_, freq) { + curr_win && curr_win.win.update && curr_win.win.update (freq); + }; + + var setEvents = function ( obj, _url ) { + obj.win.destroy = function () { + app.stopListeningFor ('DidAudioProcess', freq_cb); + app.fireEvent ('DidToggleFreqAn', _url, null); + + // if (obj && obj.type === undefined) { + if (obj && obj === eq_win[url]) { + eq_win[url] = null; + } + + var stop = true; + for (var k in eq_win) { + if (eq_win[k]) { + stop = false; + break; + } + } + + if (stop) app.engine.wavesurfer.backend.logFrequencies = false; + }; + + app.listenFor ('DidAudioProcess', freq_cb); + app.fireEvent ('DidToggleFreqAn', _url, curr_win); + app.engine.wavesurfer.backend.logFrequencies = true; + }; + + if (!type) + { + var makePopup = function ( dat ) { + var extra = ''; + if (dat && dat[0]) { + dat[0] = Math.max (0, dat[0] - 200) >> 0; + dat[1] = Math.max (0, dat[1]) >> 0; + + extra = ',left=' + dat[0] + ',top=' + dat[1]; + } + + var wnd = window.open ('/' + url + '.html', title, "directories=no,titlebar=no,toolbar=no,"+ + "location=no,status=no,menubar=no,scrollbars=no,resizable=no,width=600,height=188" + extra); + + if (!wnd) { + OneUp ('Please allow pop-ups for AudioMass!', 3600, 'pk_r'); + return ; + } + + eq_win[url] = { + type : type, + el : null, + win : wnd, + destroy : function () { + wnd && wnd.close && wnd.close (); + } + }; + + curr_win = eq_win[url]; + + // wnd.moveTo(500, 100); + + setEvents ( curr_win, url ); + }; + + if (!toggled) makePopup (toggle); + else setTimeout(function(){makePopup (toggle)}, 130); + } + else if (type === 1) + { + var iframe = document.createElement ('iframe'); + iframe.className = 'pk_frqan'; + iframe.id = 'pk_fr' + url; + + if (app.ui.BarBtm.on) { + var ch = app.ui.BarBtm.el.childNodes; + var lw = 0; + for (var ji = 0; ji < ch.length; ++ji) { + lw += ch[ji].clientWidth + 18; + } + + iframe.style.left = lw + 'px'; + } + + app.ui.BarBtm.el.appendChild( iframe ); + app.ui.BarBtm.Show (); + + eq_win[url] = { + type : type, + el : iframe, + win : null, + destroy : function () { + iframe.parentNode.removeChild ( iframe ); + iframe = null; + + var ch = app.ui.BarBtm.el.childNodes; + if (ch.length === 0) { + app.ui.BarBtm.Hide (); + return ; + } + + setTimeout(function () { + var lw = 0; + for (var ji = 0; ji < ch.length; ++ji) { + if (!ch[ji] || !ch[ji].parentNode) continue; + + if (ch[ji].offsetTop > -20) { + ch[ji].style.top = '0px'; + ch[ji].style.left = lw + 'px'; + } + + lw += ch[ji].clientWidth + 18; + } + },198); + // -- + } + }; + + curr_win = eq_win[url]; + + iframe.onload = function (e) { + if (curr_win && curr_win.type === type) + { + curr_win.win = iframe.contentWindow; + setEvents ( curr_win, url ); + } + }; + iframe.src = '/' + url + '.html?iframe=1'; + } + // --- + + }); + + // ---- + }; + + PKAE._deps.uifx = PKUI_FX; + +})( window, document, PKAudioEditor ); \ No newline at end of file diff --git a/audiomass-editor/src/ui.js b/audiomass-editor/src/ui.js new file mode 100755 index 0000000..f8d81d0 --- /dev/null +++ b/audiomass-editor/src/ui.js @@ -0,0 +1,3095 @@ +(function ( w, d, PKAE ) { + 'use strict'; + + // + // MAIN UI CLASS + var PKUI = function( app ) { + var q = this; + + this.el = app.el; + + // if mobile add proper class + this.el.className += ' pk_app' + (app.isMobile ? ' pk_mob' : ''); + + // hold refferences to the event functions + this.fireEvent = app.fireEvent; + this.listenFor = app.listenFor; + + // keep track of the active UI element + this.InteractionHandler = { + on : false, + by : null, + arr : [], + + check: function ( _name ) { + if (this.on && this.by !== _name) { + return (false); + } + return (true); + }, + + checkAndSet: function ( _name ) { + if (!this.check (_name)) + return (false); + + this.on = true; + this.by = _name; + + return (true); + }, + + forceSet: function ( _name ) { + if (this.on) + { + this.arr.push ({ + on: this.on, + by: this.by + }); + } + + this.on = true; + this.by = _name; + }, + + forceUnset: function ( _name ) { + if (this.check (_name)) + { + var prev = this.arr.pop (); + if (prev) + { + this.on = prev.on; + this.by = prev.by; + } + else + { + this.on = false; + this.by = null; + } + } + // --- + } + }; + + if (app.isMobile) + { + d.body.className = 'pk_stndln'; + var fxd = d.createElement ('div'); + fxd.className = 'pk_fxd'; + fxd.appendChild (this.el); + + d.body.appendChild (fxd); + + _makeMobileScroll (this); + } + + this.KeyHandler = new app._deps.keyhandler ( this ); // initializing keyhandler + this.TopHeader = new _makeUITopHeader ( _topbarConfig ( app ), this ); // topmost menu + this.Toolbar = new _makeUIToolbar ( this ); // main toolbar and controls + this.footer = new _makeUIMainView ( this, app ); + this.BarBtm = new _makeUIBarBottom (this, app); + + this.Dock = function ( id, arg1, arg2 ) { + app.fireEvent (id, arg1, arg2); + }; + + app.listenFor ('ShowError', function( message ) { + new PKSimpleModal ({ + title : 'Oops! Something is not right', + clss:'pk_modal_anim', + ondestroy : function( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback ('modalTempErr'); + }, + buttons:[], + body:'

' + message + '

', + setup:function( q ) { + app.fireEvent ('RequestPause'); + app.fireEvent( 'RequestRegionClear'); + + app.ui.InteractionHandler.checkAndSet ('modal'); + app.ui.KeyHandler.addCallback ('modalTempErr', function ( e ) { + q.Destroy (); + }, [27]); + } + }).Show (); + }); + + app.listenFor ('RequestKeyDown', function ( key ) { + q.KeyHandler.keyDown ( key, null ); + q.KeyHandler.keyUp ( key ); + }); + }; + + + //top bar config list + function _topbarConfig ( app, ui ) { + return [ + { + name:'File', + children : [ + { + name: 'Export / Download', + action: function () { + new PKSimpleModal({ + title:'Export / Download', + + ondestroy: function( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback ('modalTemp'); + }, + + buttons:[ + { + title:'Export', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var input = q.el_body.getElementsByTagName('input')[0]; + var value = input.value.trim(); + + var format = 'mp3'; + var kbps = 128; + var export_sel = false; + var stereo = false; + + var radios = q.el_body.getElementsByClassName ('pk_check'); + var l = radios.length; + while (l-- > 0) { + if (radios[l].checked) + { + if (radios[l].name == 'frmtex') + { + format = radios[l].value; + } + else if (radios[l].name == 'xport') + { + if (radios[l].value === 'sel') + { + var region = app.engine.wavesurfer.regions.list[0]; + if (!region) export_sel = false; + else export_sel = [region.start, region.end]; + } + } + else if (radios[l].name == 'chnl') + { + if (radios[l].value === 'stereo') + { + stereo = true; + } + } + else + { + kbps = radios[l].value / 1; + } + } + } + + if (format == 'flac') + { + kbps = document.getElementById('flac-comp').value / 1; + } + + app.engine.DownloadFile ( value, format, kbps, export_sel, stereo ); + q.Destroy (); + // - + } + } + ], + body:'
' + + '
'+ + + '
'+ + ''+ + '' + + ''+ + '' + + ''+ + '' + + '
' + + + '
'+ + '' + + ''+ + ''+ + ''+ + '
'+ + + '' + + + '
' + + ''+ + ''+ + ''+ + ''+ + '
'+ + '
' + + ''+ + ''+ + ''+ + '
', + + setup:function( q ) { + var wv = PKAudioEditor.engine.wavesurfer; + //console.log( document.getElementById('frmtex') ); + + // if no region + var region = wv.regions.list[0]; + if (!region) { + var lbl = q.el_body.getElementsByClassName('pk_lblmp3')[0]; + lbl.className = 'pk_dis'; + } + + var chan_num = wv.backend.buffer.numberOfChannels; + if (chan_num === 2) { + q.el_body.getElementsByClassName('pk_stereo')[0].checked = true; + } + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet ('modal'); + app.ui.KeyHandler.addCallback ('modalTemp', function ( e ) { + q.Destroy (); + }, [27]); + + setTimeout(function() { + if (!q.el) return ; + var inputtxt = q.el.getElementsByTagName('input')[0]; + inputtxt && inputtxt.select (); + + var format = document.getElementById('frmtex'); + var mp3conf = document.getElementById('frmtex-mp3'); + var flacconf = document.getElementById('frmtex-flac'); + + document.getElementById('flac-comp').oninput = function() { + this.parentNode.getElementsByTagName('span')[0].innerText = this.value; + }; + + format && format.addEventListener('change', function(e){ + var inputs = this.getElementsByTagName('input'); + for (var i = 0; i < inputs.length; ++i) + { + if (inputs[i].checked) + { + if (inputs[i].value === 'mp3') + { + mp3conf.style.display = 'block'; + flacconf.style.display = 'none'; + inputtxt.value = inputtxt.value.replace('.wav', '.mp3').replace('.flac', '.mp3'); + } + else if (inputs[i].value === 'flac') + { + mp3conf.style.display = 'none'; + flacconf.style.display = 'block'; + inputtxt.value = inputtxt.value.replace('.mp3', '.flac').replace('.wav', '.flac'); + } + else + { + mp3conf.style.display = 'none'; + flacconf.style.display = 'none'; + inputtxt.value = inputtxt.value.replace('.mp3', '.wav').replace('.flac', '.wav'); + } + } + } + }, false); + + },20); + } + }).Show(); + }, + clss: 'pk_inact', + setup: function ( obj ) { + obj.setAttribute('data-id', 'dl'); + + app.listenFor ('DidUnloadFile', function () { + obj.classList.add ('pk_inact'); + }); + app.listenFor ('DidLoadFile', function () { + obj.classList.remove ('pk_inact'); + }); + } + }, + + { + name: 'Load from Computer', + type: 'file', + action: function ( e ) { + app.fireEvent ('RequestLoadLocalFile'); + } + }, + + { + name: 'Load Sample File', + action: function ( e ) { + app.engine.LoadSample (); + } + }, + + { + name: 'Load From URL', + action: function ( e ) { + new PKSimpleModal({ + title:'Load audio from remote url', + + ondestroy: function( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback ('modalTemp'); + app.ui.KeyHandler.removeCallback ('modalTempEnter'); + }, + + buttons:[ + { + title:'Load Asset', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var input = q.el_body.getElementsByTagName('input')[0]; + var value = input.value.trim(); + + function isURL ( str ) { + var pattern = new RegExp('^((https?:)?\\/\\/)?'+ // protocol + '(?:\\S+(?::\\S*)?@)?' + // authentication + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string + '(\\#[-a-z\\d_]*)?$','i'); // fragment locater + if (!pattern.test(str)) { + return false; + } else { + return true; + } + }; + + if (isURL (value)) + { + // LOAD FROM URL.... + app.engine.LoadURL ( value ); + q.Destroy (); + } + else + { + OneUp ('Invalid URL entered', 1100); + } + // - + } + } + ], + body:'' + + '', + setup:function( q ) { + + app.fireEvent ('RequestPause'); + app.ui.InteractionHandler.checkAndSet ('modal'); + app.ui.KeyHandler.addCallback ('modalTemp', function ( e ) { + q.Destroy (); + }, [27]); + + app.ui.KeyHandler.addCallback ('modalTempEnter', function ( e ) { + q.els.bottom[0].click (); + }, [13]); + + setTimeout(function() { + q.el && q.el.getElementsByTagName('input')[0].focus (); + },20); + } + }).Show(); + } + // --- + }, + + { + name: 'New Recording', + action: function ( e ) { + app.fireEvent('RequestActionNewRec'); + } + }, + + { + name: 'Save Draft Locally', + clss: 'pk_inact', + action: function ( e ) { + if (!app.engine.is_ready) return ; + + var saving = function ( type, name ) { + var buff = app.engine.wavesurfer.backend.buffer; + + if (type === 'copy') buff = app.engine.GetCopyBuff (); + else if (type === 'sel') buff = app.engine.GetSel (); + + var func = function ( fls ) { + var rr = Math.random().toString(36).substring(7); + + fls.SaveSession (buff, rr, name); + app.stopListeningFor ('DidOpenDB', func); + }; + + app.listenFor ('DidOpenDB', func); + + if (!app.fls.on) app.fls.Init (function(err){if(err){alert("db error")}}); + else app.fireEvent ('DidOpenDB', app.fls); + }; + + // modal that asks for - full file, selection, copy buffer + new PKSimpleModal ({ + title : 'Save Local Draft of...', + + ondestroy : function( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback ('modalTempErr'); + }, + + buttons:[ + { + title:'Save', + clss:'pk_modal_a_accpt', + callback: function( q ) { + var type = 'whole'; + var input = q.el_body.getElementsByTagName ('input'); + var name = input[ input.length - 1 ].value; + if (name) { + name = name.trim (); + if (name.length >= 100) name = name.substr(0,99).trim(); + if (name.length === 0) name = null; + } + else { + name = null; + } + + for (var i = 0; i < input.length; ++i) { + if (input[i].checked) + { + type = input[i].value; + break; + } + } + + saving (type, name); + + q.Destroy (); + } + } + ], + + body:'

Please choose source...

' + + '
'+ + '' + + ''+ + ''+ + ''+ + '
'+ + + '
' + + '
', + + setup:function( q ) { + // check if selection + var wv = app.engine.wavesurfer; + + // if no region + var region = wv.regions.list[0]; + var lblr = q.el_body.getElementsByClassName('pk_lblsel')[0]; + if (!region) { + lblr.className = 'pk_dis'; + } else { + q.el_body.getElementsByClassName('pk_check')[1].checked = true; + lblr.childNodes[1].textContent = app.ui.formatTime(region.start) + ' to ' + app.ui.formatTime(region.end); + } + + // if no copy buffer + var copy = app.engine.GetCopyBuff (); + if (!copy) { + var lbl = q.el_body.getElementsByClassName('pk_lblsel2')[0]; + lbl.className = 'pk_dis'; + } + + if (!app.isMobile) + { + setTimeout(function() { + q.el && q.el.getElementsByClassName('pk_txt')[0].focus (); + },20); + } + + app.fireEvent ('RequestPause'); + + app.ui.InteractionHandler.checkAndSet ('modal'); + app.ui.KeyHandler.addCallback ('modalTempErr', function ( e ) { + q.Destroy (); + }, [27]); + } + }).Show (); + + return ; + }, + + setup: function ( obj ) { + app.listenFor ('DidUnloadFile', function () { + obj.classList.add ('pk_inact'); + }); + app.listenFor ('DidLoadFile', function () { + obj.classList.remove ('pk_inact'); + }); + + app.listenFor ('DidStoreDB', function ( obj, e ) { + var name = obj.id; + var txt = '
id: ' + name + '
'+ + '
durr: ' + obj.durr + 's'+ + '   '+ + 'chan: ' + (obj.chans === 1 ? 'mono' : 'stereo') + '
'+ + '
'; + + new PKSimpleModal ({ + title : 'Succesfully Stored', + + ondestroy : function( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback ('modalTempErr'); + }, + + buttons:[ + { + title:'OPEN IN NEW WINDOW', + callback: function( q ) { + window.open ( window.location.pathname + '?local=' + name); + + q.Destroy (); + } + } + ], + + body:'

Open in new window?

' + txt, + setup:function( q ) { + app.fireEvent ('RequestPause'); + app.fireEvent( 'RequestRegionClear'); + + app.ui.InteractionHandler.checkAndSet ('modal'); + app.ui.KeyHandler.addCallback ('modalTempErr', function ( e ) { + q.Destroy (); + }, [27]); + } + }).Show (); + }); + } + }, + + { + name: 'Open Local Drafts', + action: function ( e ) { + + var datenow = new Date (); + var time_ago = function ( arg ) { + var a = (datenow - arg) / 1E3 >> 0; + if (59 >= a) return datenow = 1 < a ? 's' : '', a + ' second' + datenow + ' ago'; + if (60 <= a && 3599 >= a) return a = Math.floor(a / 60), a + ' minute' + (1 < a ? 's' : '') + ' ago'; + if (3600 <= a && 86399 >= a) return a = Math.floor(a / 3600), a + ' hour' + (1 < a ? 's' : '') + ' ago'; + if (86400 <= a && 2592030 >= a) return a = Math.floor(a / 86400), a + ' day' + (1 < a ? 's' : '') + ' ago'; + if (2592031 <= a) return a = Math.floor(a / 2592E3), a + ' month' + (1 < a ? 's' : '') + ' ago'; + }; + var func = function ( fls ) { + fls.ListSessions(function( ret ) { + + var msg = ''; + if (ret.length === 0) { + msg += 'No drafts found...'; + } + else + { + for (var i = 0; i < ret.length; ++i) + { + var curr = ret[i]; + var date = new Date(curr.created); + var datestr = (date.getMonth()+1) + '/' + + date.getDate() + '/' + + date.getFullYear() + " " + + date.getHours() + ":" + + date.getMinutes() + ":" + + date.getSeconds(); + var agostr = time_ago (date); + var filename = curr.name || '-'; + var duration = curr.durr; + var thumb = curr.thumb; + var chns = (curr.chans === 1 ? 'mono' : 'stereo'); + + msg += '
'+ + '
name:' + filename + '
' + + '
id:' + curr.id + '
chn:'+ chns +'
' + + 'date:' + datestr + '
'+ agostr +'
' + + 'durr:' + duration + 's
' + + + '' + + 'PLAY' + + 'Open'; + + if (app.engine.is_ready) { + msg += 'Append to Current Track'; + } + msg += 'Del'; + msg += '
'; + } + } + + var modal; + var closeModal = function ( val, val2 ) { + if (val2 === 2 || val2 === 3) return ; + + modal.Destroy (); + modal = null; + }; + + var set_act_btn = function ( name, state ) { + var act; + if (!state) { + act = modal.el_body.getElementsByClassName('pk_act')[0]; + if (act) { + act.classList.remove ('pk_act'); + } + } + else { + var el = document.getElementById ('pk_' + name); + if (el) { + act = el.getElementsByClassName ('pk_lcla2')[0]; + act && act.classList.add ('pk_act'); + } + } + // -- + }; + + app.listenFor ('_lclStart', set_act_btn); + + modal = new PKSimpleModal ({ + title : 'Local Drafts', + clss : 'pk_bigger', + + ondestroy : function( q ) { + + app.fireEvent ('_lclStop'); + + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback ('modalTempErr'); + app.stopListeningFor ('LoadDraft', closeModal); + app.stopListeningFor ('_lclStart', set_act_btn); + }, + + buttons:[], + + body:'
' + msg + '
', + setup:function( q ) { + app.fireEvent ('RequestPause'); + app.fireEvent( 'RequestRegionClear'); + + app.listenFor ('LoadDraft', closeModal); + + app.ui.InteractionHandler.checkAndSet ('modal'); + app.ui.KeyHandler.addCallback ('modalTempErr', function ( e ) { + q.Destroy (); + }, [27]); + } + }); + + modal.Show (); + }); + + app.stopListeningFor ('DidOpenDB', func); + }; + + app.listenFor ('DidOpenDB', func); + + if (!app.fls.on) app.fls.Init (function(err){if(err){alert("db error")}}); + else app.fireEvent ('DidOpenDB', app.fls); + }, + setup: function () { + var source = {}; + + app.listenFor ('_lclStop', function ( name, append ) { + if (source.src) { + source.src.stop (); + source.src.disconnect (); + source.src.onended = null; + source.aud.close && source.aud.close (); + source = {}; + } + }); + + app.listenFor ('LoadDraft', function ( name, append ) { + app.fls.Init (function (err) { + if (err) return ; + + if (append === 2) + { + if (source.id === name) + { + app.fireEvent ('_lclStart', source.id, 0); + source.src.stop (); + source.src.disconnect (); + source.src.onended = null; + source.aud.close && source.aud.close (); + source = {}; + } + + app.fls.DelSession (name, function (name) { + var id = 'pk_' + name; + var el = document.getElementById (id); + + if (el) + { + if ( el.parentNode.children.length === 1 ) { + el.parentNode.innerHTML = 'No drafts found...'; + } + else el.parentNode.removeChild(el); + + + el = null; + } + }); + return ; + } + + if (append === 3) + { + if (source.id) { + var xt = false; + if (source.id === name) xt = true; + + app.fireEvent ('_lclStart', source.id, 0); + source.src.stop (); + source.src.disconnect (); + source.src.onended = null; + source.aud.close && source.aud.close (); + + source = {}; + + if (xt) return ; + } + + // generate audio context here... + var aud_cont = new (w.AudioContext || w.webkitAudioContext)(); + if (aud_cont && aud_cont.state == 'suspended') { + aud_cont.resume && aud_cont.resume (); + } + + app.fls.GetSession (name, function ( e ) { + if(e && e.id === name ) + { + source.id = e.id; + source.aud = aud_cont; + source.src = app.engine.PlayBuff (e.data, e.chans, e.samplerate, aud_cont); + if (!source.src) { + source.aud && source.aud.close && source.aud.close (); + source = {}; + + return ; + } + + source.src.onended = function ( e ) { + app.fireEvent ('_lclStart', source.id, 0); + source.src.stop (); + source.src.disconnect (); + source.src.onended = null; + source.aud.close && source.aud.close (); + + source = {}; + }; + + app.fireEvent ('_lclStart', e.id, 1); + } + }); + return ; + } + + var overwrite = (function ( app, name, append ) { + return function () { + app.fls.GetSession (name, function ( e ) { + if(e && e.id === name ) + { + app.engine.wavesurfer.backend._add = append ? 1 : 0; + app.engine.LoadDB ( e ); + } + }); + }; + })( app, name, append ); + + // --- ask if we want to click the first one + if (app.engine.is_ready && !append) + { + var mm = new PKSimpleModal ({ + title : 'Open in Existing?', + body : '
Open in new window, or in the current one?
', + buttons:[ + { + title:'OPEN', + clss:'pk_modal_a_accpt', + callback: function( q ) { + overwrite (); + + q.Destroy (); + } + }, + { + title:'OPEN IN NEW', + clss:'pk_modal_a_accpt', + callback: function( q ) { + window.open (window.location.pathname + '?local=' + name); + q.Destroy (); + } + } + ], + setup: function ( q ) { + app.ui.InteractionHandler.checkAndSet ('mm'); + app.ui.KeyHandler.addCallback ('mmErr', function ( e ) { + q.Destroy (); + }, [27]); + }, + ondestroy: function ( q ) { + overwrite = null; + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback ('mmErr'); + } + }); + + setTimeout(function() { mm.Show (); },0); + return ; + } + + overwrite (); + // -- + }); + }); + // --- + } + } + ] + }, + { + name:'Edit', + children:[ + { + name: 'Undo Shft+Z', + clss: 'pk_inact', + action: function () { + app.fireEvent ('StateRequestUndo'); + }, + setup: function ( obj ) { + app.listenFor ('DidStateChange', function ( undo_states, redo_states ) { + if (undo_states.length === 0) + { + obj.innerHTML = 'Undo Shft+Z'; + obj.classList.add ('pk_inact'); + } + else + { + obj.innerHTML = 'Undo ' + undo_states[undo_states.length - 1].desc + 'Shft+Z'; + obj.classList.remove ('pk_inact'); + } + }); + } + }, + + { + name: 'Redo Shft+Y', + clss: 'pk_inact', + action: function () { + app.fireEvent ('StateRequestRedo'); + }, + setup: function ( obj ) { + app.listenFor('DidStateChange', function ( undo_states, redo_states ) { + if (redo_states.length === 0) + { + obj.innerHTML = 'Redo Shft+Y'; + obj.classList.add ('pk_inact'); + } + else + { + obj.innerHTML = 'Redo ' + redo_states[0].desc + 'Shft+Y'; + obj.classList.remove ('pk_inact'); + } + }); + } + }, + + { + name: 'Play Space', + action: function () { + app.fireEvent ('RequestPlay'); + } + }, + + { + name: 'Stop', + action: function () { + app.fireEvent ('RequestStop'); + } + }, + + { + name: 'Select All Shft+A', + action: function () { + app.fireEvent ('RequestSelect'); + } + }, + + { + name: 'Deselect All ~', + action: function () { + app.fireEvent ('RequestDeselect'); + } + }, + + { + name : 'Channel Info/Flip', + action : function () { + app.fireEvent ('RequestActionFXUI_Flip'); + }, + clss: 'pk_inact', + setup: function ( obj ) { + app.listenFor ('DidUnloadFile', function () { + obj.classList.add ('pk_inact'); + }); + app.listenFor ('DidLoadFile', function () { + obj.classList.remove ('pk_inact'); + }); + } + } + ] + }, + { + name:'Effects', + children:[ + { + name:'Gain', + action:function () { + app.fireEvent ('RequestFXUI_Gain'); + } + }, + + { + name:'Fade In', + action:function () { + app.fireEvent ('RequestActionFX_FadeIn'); + } + }, + + { + name:'Fade Out', + action:function () { + app.fireEvent ('RequestActionFX_FadeOut'); + } + }, + + { + name: "Noise Reduction (Voice)", + action: function () { + app.fireEvent("RequestActionFX_NoiseRNN"); + }, + }, + + { + name : 'Paragraphic EQ', + action:function () { + app.fireEvent ('RequestActionFXUI_ParaGraphicEQ'); + } + }, + + { + name:'Compressor', + action:function () { + app.fireEvent ('RequestActionFXUI_Compressor'); + } + }, + + + { + name : 'Normalize', + action:function () { + app.fireEvent ('RequestActionFXUI_Normalize'); + } + }, + + { + name : 'Graphic EQ', + action:function () { + app.fireEvent ('RequestActionFXUI_GraphicEQ', 10); + } + }, + + { + name : 'Graphic EQ (20 bands)', + action:function () { + app.fireEvent ('RequestActionFXUI_GraphicEQ', 20); + } + }, + + { + name : 'Hard Limiter', + action:function () { + app.fireEvent ('RequestActionFXUI_HardLimiter'); + } + }, + + { + name : 'Delay', + action:function () { + app.fireEvent ('RequestActionFXUI_Delay'); + } + }, + + { + name:'Distortion', + action:function () { + app.fireEvent ('RequestActionFXUI_Distortion'); + } + }, + + + { + name:'Reverb', + action:function () { + app.fireEvent ('RequestActionFXUI_Reverb'); + } + }, + + { + name : 'Speed Up / Slow Down (pitch)', + action:function () { + app.fireEvent ('RequestActionFXUI_Speed'); + } + }, + + { + name : 'Playback Rate', + action:function () { + app.fireEvent ('RequestActionFXUI_Rate'); + } + }, + + { + name : 'Reverse', + action : function () { + app.fireEvent ('RequestActionFX_Reverse'); + } + }, + + { + name : 'Invert', + action : function () { + app.fireEvent ('RequestActionFX_Invert'); + } + }, + + { + name : 'Remove Silence', + action : function () { + app.fireEvent ('RequestActionFX_RemSil'); + } + } + + ] + }, + { + name:'View', + children:[ + { + name:'Follow Cursor ✔', + action: function ( obj ) { + app.fireEvent ('RequestViewFollowCursorToggle'); + }, + setup: function ( obj ) { + // perhaps read from stored settings? + + app.listenFor ('DidViewFollowCursorToggle', function ( val ) { + var txt = 'Follow Cursor'; + + if (val) { + obj.innerHTML = txt + ' ✔'; + } else { + obj.textContent = txt; + } + }); + } + }, + + { + name:'Peak Separators ✔', + action: function ( obj ) { + app.fireEvent ('RequestViewPeakSeparatorToggle'); + }, + setup: function ( obj ) { + app.listenFor ('DidViewPeakSeparatorToggle', function ( val ) { + var txt = 'Peak Separators'; + if (val) { + obj.innerHTML = txt + ' ✔'; + } else { + obj.textContent = txt; + } + }); + } + }, + + { + name:'Timeline ✔', + action: function ( obj ) { + app.fireEvent ('RequestViewTimelineToggle'); + }, + setup: function ( obj ) { + app.listenFor ('DidViewTimelineToggle', function ( val ) { + var txt = 'Timeline'; + if (val) { + obj.innerHTML = txt + ' ✔'; + } else { + obj.textContent = txt; + } + }); + } + }, + + { + name:'---' + }, + + { + name:'Frequency Analyser', + action: function ( obj ) { + app.fireEvent ('RequestShowFreqAn', 'eq', [1]); + }, + setup: function ( obj ) { + app.listenFor ('DidToggleFreqAn', function ( url, val ) { + if (url !== 'eq') return ; + + var txt = 'Frequency Analyser'; + if (val) { + obj.innerHTML = txt + ' ✔'; + } else { + obj.textContent = txt; + } + }); + } + }, + + { + name:'Spectrum Analyser', + action: function ( obj ) { + app.fireEvent ('RequestShowFreqAn', 'sp', [1]); + }, + setup: function ( obj ) { + app.listenFor ('DidToggleFreqAn', function ( url, val ) { + if (url !== 'sp') return ; + + var txt = 'Spectrum Analyser'; + if (val) { + obj.innerHTML = txt + ' ✔'; + } else { + obj.textContent = txt; + } + }); + } + }, + + { + name:'Tempo Tools', + action: function ( obj ) { + app.fireEvent ('RequestActionTempo'); + } + }, + + { + name:'ID3 Tags', + action: function ( obj ) { + app.fireEvent ('RequestActionID3'); + } + }, + + { + name:'---' + }, + + { + name:'Center to Cursor [Tab]', + action: function ( obj ) { + app.fireEvent ('RequestViewCenterToCursor'); + } + }, + + { + name:'Reset Zoom [0]', + action: function ( obj ) { + app.fireEvent ('RequestZoomUI', 0); + } + } + + ] + }, + { + name:'Help', + children:[ + { + name : 'Store Offline Version', + action : function () { + if (window.location.href.indexOf('-cache') > 0) { + + function onUpdateReady ( e ) { + if (confirm ('Would you like to refresh the page to load the newer version?')) + window.location.reload(); + } + function downLoading ( e ) { + OneUp ('Downloading newer version', 1500); + } + + window.applicationCache.onupdateready = onUpdateReady; + window.applicationCache.ondownloading = downLoading; + + if(window.applicationCache.status === window.applicationCache.UPDATEREADY) { + onUpdateReady (); + } + + window.applicationCache.update (); + + return ; + } + + var message = 'This will open a new window that will try to store a local version in your browser'; // nicer text + + new PKSimpleModal ({ + title : 'Open Offline Version?', + + ondestroy : function( q ) { + app.ui.InteractionHandler.on = false; + app.ui.KeyHandler.removeCallback ('modalTempErr'); + }, + + buttons:[ + { + title:'OPEN', + callback: function( q ) { + window.open ('/index-cache.html'); + q.Destroy (); + } + } + ], + body:'

' + message + '

', + setup:function( q ) { + app.fireEvent ('RequestPause'); + app.fireEvent( 'RequestRegionClear'); + + app.ui.InteractionHandler.checkAndSet ('modal'); + app.ui.KeyHandler.addCallback ('modalTempErr', function ( e ) { + q.Destroy (); + }, [27]); + } + }).Show (); + // - + }, + setup: function ( obj ) { + if (window.location.href.indexOf('-cache') > 0) + { + obj.innerHTML = 'Update Offline Version'; + } + } + }, + + { + name:'---' + }, + + { + name : 'About', + action : function () { + window.open ('/about.html'); + } + }, + + { + name : 'See Welcome Message', + action : function () { + PKAudioEditor._deps.Wlc (); + } + }, + // { + // name : 'About AudioMass', + // action : function () { + // window.open ('/about.html'); + // } + // }, + + // { + // name:'---' + // }, + + { + name : 'SourceCode on Github', + action : function () { + window.open ('https://github.com/pkalogiros/audiomass'); + } + } + ] + } + ]; + }; + + // + // TOP-BAR CLASS + // + function _makeUITopHeader ( menu_tree, UI ) { + var header = d.createElement ( 'div' ); + header.className = 'pk_hdr pk_noselect'; + + var _name = 'TopHeader', + _default_class = 'pk_btn pk_noselect'; + + var target_index = -1; + var target_el = null; + var target_el_old = null; + var target_option = null; + var top_els = []; + var q = this; + + // recursively build the interface + function build_menus ( parent_el, tree_obj, level ) { + for (var i = 0; i < tree_obj.length; ++i) + { + var btn_container = d.createElement ( 'div' ); + var curr_obj = tree_obj[i]; + + if (level === 0) + { + btn_container.className = _default_class; + var btn = d.createElement ( 'button' ); + btn.innerHTML = curr_obj.name; + btn_container.appendChild ( btn ); + } + else + { + btn_container.className = 'pk_menu_el'; + var btn = d.createElement ( 'button' ); + btn.className = 'pk_opt ' + (curr_obj.clss ? curr_obj.clss : ''); + btn.setAttribute ( 'tab-index', '-1' ); + btn.setAttribute ( 'data-index', i ); + btn.innerHTML = curr_obj.name; + btn_container.appendChild ( btn ); + + if (curr_obj.action) + { + (function ( btn, action ) { + btn.onclick = function ( obj ) { + if (this.classList.contains('pk_inact')) return ; + + q.closeMenu (); + action ( obj ); + }; + })( btn, curr_obj.action ); + } + if (curr_obj.setup) + { + curr_obj.setup ( btn ); + } + } + parent_el.appendChild ( btn_container ); + + if (level === 0) + top_els[i] = btn_container.childNodes[0]; + + if (curr_obj.children) + { + var ch = curr_obj.children; + var list = d.createElement('div'); + list.className = 'pk_menu'; + + build_menus ( list, curr_obj.children, level + 1 ); + btn_container.appendChild ( list ); + } + // --- + } + }; + build_menus ( header, menu_tree, 0 ); + + this.getOpenElement = function () { + return target_el; + }; + this.closeMenu = function() { + if (!target_el) return ; + + target_el.parentNode.className = _default_class; + target_el = target_el_old = null; + + if (target_option) + { + target_option.classList.remove ('pk_act'); + target_option = null; + } + + UI.InteractionHandler.on = false; + d.removeEventListener ( 'mouseup', mouseup ); + + // de-register keys + UI.KeyHandler.removeCallback (_name + 1); + UI.KeyHandler.removeCallback (_name + 2); + UI.KeyHandler.removeCallback (_name + 3); + UI.KeyHandler.removeCallback (_name + 4); + UI.KeyHandler.removeCallback (_name + 5); + UI.KeyHandler.removeCallback (_name + 6); + }; + + this.openMenu = function ( index, is_mouse ) { + if (target_el) { + target_el.parentNode.className = _default_class; + } + + if (index === -1) { + index = target_index === -1 ? 0 : target_index; + } + + var curr_target = top_els[ index ]; + target_el = curr_target; + + var parent = curr_target.parentNode; + var left = parent.getBoundingClientRect ().left; + var max = window.innerWidth; + var offset = 0; + + if ( max - left < 200 ) + { + offset = (264 - (max - left)) >> 0; + + if (offset > 1) + parent.getElementsByClassName ('pk_menu')[0].style.left = (-offset / 2) + 'px'; + } + + parent.className += ' pk_vis'; + setTimeout(function() { + if (target_el === curr_target) + parent.className += ' pk_act'; + },0); + + target_index = index; + + UI.InteractionHandler.checkAndSet (_name); + + if (!is_mouse) + d.addEventListener ( 'mouseup', mouseup, false ); + + // register keystrokes + UI.KeyHandler.addCallback (_name + 1, function ( key ) { + if (target_index === 0) + target_index = top_els.length; + + q.closeMenu (); + q.openMenu ( target_index - 1 ); + }, [37]); + UI.KeyHandler.addCallback (_name + 2, function ( key ) { + if (target_index === top_els.length - 1) + target_index = -1; + + q.closeMenu (); + q.openMenu ( target_index + 1 ); + }, [39]); + UI.KeyHandler.addCallback (_name + 3, function ( key ) { + q.closeMenu (); + }, [27]); + UI.KeyHandler.addCallback (_name + 4, function ( key, m, e ) { + if (!target_option) + { + var els = target_el.parentNode.getElementsByClassName ('pk_opt'); + if (els[0]) { + target_option = els[0]; + target_option.classList.add ('pk_act'); + } + } + else + { + var ind = target_option.getAttribute ('data-index')/1; + target_option.classList.remove ('pk_act'); + + target_option = target_el.parentNode.getElementsByClassName ('pk_opt'); + if (ind - 1 < 0) + { + target_option = target_option[target_option.length - 1]; + } + else + { + target_option = target_option[ind - 1]; + } + target_option.classList.add ('pk_act'); + } + }, [38]); + UI.KeyHandler.addCallback (_name + 5, function ( key, m, e ) { + if (!target_option) + { + var els = target_el.parentNode.getElementsByClassName ('pk_opt'); + if (els[0]) { + target_option = els[0]; + target_option.classList.add ('pk_act'); + } + } + else + { + var ind = target_option.getAttribute ('data-index')/1; + target_option.classList.remove ('pk_act'); + + target_option = target_el.parentNode.getElementsByClassName ('pk_opt'); + if (target_option.length <= ind + 1) + { + target_option = target_option[0]; + } + else + { + target_option = target_option[ind + 1]; + } + target_option.classList.add ('pk_act'); + } + }, [40]); + UI.KeyHandler.addCallback (_name + 6, function ( key ) { + if (target_option) + target_option.click(); + else + q.closeMenu (); + }, [13]); + + return (true); + }; + + UI.listenFor ('DidReadyFire', function () { + q.closeMenu (); + }); + + // register hot keys for opening the menu + function _checkForAct( x ) { + if (target_el == x || !x) return (false); + + var par = x.parentNode; + while (par && target_el) { + if (target_el.parentNode == par) { + return (false); + } + par = par.parentNode; + } + + var l = top_els.length; + while(l-- > 0) { + if (top_els[l] === x) { + return q.openMenu (l, true); + } + } + return (false); + } + + // now make the buttons interactive + var mousemove = function ( e ) { + if (!UI.InteractionHandler.check (_name)) { + return (false); + } + + if (target_el || (UI.InteractionHandler.on && UI.InteractionHandler.by === _name) ) + { + var x = e.target || e.srcElement; + + if (x.className.indexOf('pk_opt') >= 0) + { + if (target_option) + target_option.classList.remove ('pk_act'); + + target_option = x; + target_option.classList.add ('pk_act'); + } + else + { + if (target_option) + target_option.classList.remove ('pk_act'); + target_option = null; + } + + return _checkForAct ( x ); + } + + return (false); + }; + var mouseup = function( e ) { + var x = e.target || e.srcElement; + + if (target_el) + { + // todo check for inner menu? + var par = x; + var found = false; + while (par && target_el) { + if (target_el.parentNode == par) { + found = true; + break; + } + par = par.parentNode; + } + + if (!found || target_el_old === x) { + q.closeMenu(); + } + } + else + { + UI.InteractionHandler.on = false; + d.removeEventListener ( 'mouseup', mouseup ); + } + + target_el_old = null; + }; + + header.addEventListener ( 'mousemove', mousemove, false ); + header.addEventListener ( 'mousedown', function( e ) { + if (!UI.InteractionHandler.checkAndSet (_name)) { + return (false); + } + + d.removeEventListener ( 'mouseup', mouseup ); + + if (target_el) + { + if (!_checkForAct ( e.target || e.srcElement )) + target_el_old = target_el; + else + target_el_old = null; + + d.addEventListener ( 'mouseup', mouseup, false ); + } + else + { + target_el_old = null; + d.addEventListener ( 'mouseup', mouseup, false ); + _checkForAct ( e.target || e.srcElement ); + } + // - + }, false); + + UI.el.appendChild ( header ); + // - + }; + + + // #### + function _makeUIBarBottom ( UI, app ) { + var q = this; + + var bar_bottom_el = d.createElement ('div'); + bar_bottom_el.className = 'pk_dck'; + UI.el.appendChild( bar_bottom_el ); + + q.el = bar_bottom_el; + q.on = false; + q.height = 130; + + q.Show = function () { + q.on = true; + bar_bottom_el.style.display = 'block'; + + app.fireEvent ('RequestResize'); + }; + q.Hide = function () { + q.on = false; + bar_bottom_el.style.display = 'none'; + + app.fireEvent ('RequestResize'); + }; + }; + + function _makeUIMainView ( UI, app ) { + var q = this; + + var audio_container = d.createElement ('div'); + audio_container.className = 'pk_av_cont'; + UI.el.appendChild( audio_container ); + + + var main_audio_view = d.createElement ( 'div' ); + main_audio_view.className = 'pk_av pk_noselect'; + main_audio_view.id = 'pk_av_' + app.id; + audio_container.appendChild( main_audio_view ); + + + var footer = d.createElement ( 'div' ); + footer.className = 'pk_ftr pk_noselect'; + UI.el.appendChild( footer ); + + // make panner buttons + var btn_panner_cnt = d.createElement ('div'); + btn_panner_cnt.className = 'pk_panner pk_noselect'; + + var panner_col_left = d.createElement ('div'); + panner_col_left.className = 'pk_pan_left'; + var panner_col_right = d.createElement ('div'); + panner_col_right.className = 'pk_pan_right'; + + var btn_panner_left = d.createElement ('button'); + var btn_panner_right = d.createElement ('button'); + btn_panner_left.setAttribute ('tabIndex', -1); + btn_panner_right.setAttribute ('tabIndex', -1); + btn_panner_left.className = 'pk_pan_btn'; + btn_panner_right.className = 'pk_pan_btn'; + + btn_panner_left.innerHTML = 'L ON'; + btn_panner_right.innerHTML = 'R ON'; + + panner_col_left.appendChild ( btn_panner_left ); + panner_col_right.appendChild ( btn_panner_right ); + btn_panner_cnt.appendChild ( panner_col_left ); + btn_panner_cnt.appendChild ( panner_col_right ); + audio_container.appendChild ( btn_panner_cnt ); + + + btn_panner_left.onclick = function () { + app.fireEvent ('RequestChanToggle', 0); + this.blur(); + }; + btn_panner_right.onclick = function () { + app.fireEvent ('RequestChanToggle', 1); + this.blur(); + }; + app.listenFor ('DidChanToggle', function ( chan, val ) { + if ( chan === 0) { + if (val) + { + btn_panner_left.classList.remove ('pk_inact'); + btn_panner_left.innerHTML = 'L ON'; + } + else + { + btn_panner_left.classList.add ('pk_inact'); + btn_panner_left.innerHTML = 'L OFF'; + } + } else { + if (val) + { + btn_panner_right.classList.remove ('pk_inact'); + btn_panner_right.innerHTML = 'R ON'; + } + else + { + btn_panner_right.classList.add ('pk_inact'); + btn_panner_right.innerHTML = 'R OFF'; + } + } + }); + + // zoom btns + var btn_zoom_cnt = d.createElement ('div'); + btn_zoom_cnt.className = 'pk_zoombtn'; + + var btn_zoom_in_h = d.createElement ('button'); + btn_zoom_in_h.className = 'pk_btn pk_zoom_in_h'; + btn_zoom_in_h.innerHTML = '+Zoom In Horiz (+)'; + btn_zoom_in_h.setAttribute ('tabIndex', -1); + btn_zoom_in_h.onclick = function () { + app.fireEvent ('RequestZoomUI', 'h', -1); + this.blur(); + }; + + var btn_zoom_out_h = d.createElement ('button'); + btn_zoom_out_h.className = 'pk_btn pk_zoom_out_h pk_inact'; + btn_zoom_out_h.innerHTML = '–Zoom Out Horiz (-)'; + btn_zoom_out_h.setAttribute ('tabIndex', -1); + btn_zoom_out_h.onclick = function () { + app.fireEvent ('RequestZoomUI', 'h', 1); + this.blur(); + }; + + var btn_zoom_reset = d.createElement ('button'); + btn_zoom_reset.className = 'pk_btn pk_zoom_reset pk_inact'; + btn_zoom_reset.innerHTML = '[R] Reset Zoom (0)'; + btn_zoom_reset.setAttribute ('tabIndex', -1); + btn_zoom_reset.onclick = function () { + app.fireEvent ('RequestZoomUI', 0); + this.blur(); + }; + UI.KeyHandler.addCallback ('Key0', function ( key ) { + if (UI.InteractionHandler.on) return ; + app.fireEvent ('RequestZoomUI', 0); + }, [48]); + + UI.KeyHandler.addCallback ('KeyZO', function ( key ) { + if (UI.InteractionHandler.on) return ; + app.fireEvent ('RequestZoomUI', 'h', 1); + }, [189]); + UI.KeyHandler.addCallback ('KeyZI', function ( key ) { + if (UI.InteractionHandler.on) return ; + app.fireEvent ('RequestZoomUI', 'h', -1); + }, [187]); + + var btn_zoom_in_v = d.createElement ('button'); + btn_zoom_in_v.className = 'pk_btn pk_zoom_in_v'; + btn_zoom_in_v.innerHTML = '↕ +Zoom In Vertically'; + btn_zoom_in_v.setAttribute ('tabIndex', -1); + btn_zoom_in_v.onclick = function () { + app.fireEvent ('RequestZoomUI', 'v', -1); + this.blur(); + }; + + var btn_zoom_out_v = d.createElement ('button'); + btn_zoom_out_v.className = 'pk_btn pk_zoom_out_v'; + btn_zoom_out_v.innerHTML = '↕ –Zoom Out Vertically'; + btn_zoom_out_v.setAttribute ('tabIndex', -1); + btn_zoom_out_v.onclick = function () { + app.fireEvent ('RequestZoomUI', 'v', 1); + this.blur(); + }; + + btn_zoom_cnt.appendChild ( btn_zoom_in_h ); + btn_zoom_cnt.appendChild ( btn_zoom_out_h ); + btn_zoom_cnt.appendChild ( btn_zoom_reset ); + btn_zoom_cnt.appendChild ( btn_zoom_in_v ); + btn_zoom_cnt.appendChild ( btn_zoom_out_v ); + + footer.appendChild ( btn_zoom_cnt ); + // end of zoom btns + + var wavezoom = d.createElement ( 'div' ); + wavezoom.className = 'pk_wavescroll'; + + var wavepoint_visible = false; + var wavepoint = d.createElement ( 'div' ); + wavepoint.className = 'pk_wavepoint'; + + var wavedrag = d.createElement ( 'div' ); + var wavedrag_style = wavedrag.style; + wavedrag.className = 'pk_wavedrag pk_inact'; + + var wavedrag_left = d.createElement ( 'div' ); + wavedrag_left.className = 'pk_wavedrag_l'; + var wavedrag_right = d.createElement ( 'div' ); + wavedrag_right.className = 'pk_wavedrag_r'; + + wavezoom.appendChild ( wavepoint ); + wavedrag.appendChild ( wavedrag_left ); + wavedrag.appendChild ( wavedrag_right ); + wavezoom.appendChild ( wavedrag ); + footer.appendChild ( wavezoom ); + + var temp = 0; + var wavedrag_width = 100; + wavezoom.onclick = function( e ) { + if (window.performance.now() - temp < 20) + { + return ; + } + + var rect = e.target.getBoundingClientRect(); + var x = e.clientX - rect.left; + UI.fireEvent ('RequestPan', x, 2); + }; + + // add zoom event, and add seek event.... + UI.listenFor ('DidZoom', function ( v ) { + var e = v[0]; + var o = v[1]; + + if (e === 1) { + btn_zoom_out_h.classList.add ('pk_inact'); + btn_zoom_reset.classList.add ('pk_inact'); + } else { + btn_zoom_out_h.classList.remove ('pk_inact'); + btn_zoom_reset.classList.remove ('pk_inact'); + } + + if (v[2] != 1) { + btn_zoom_reset.classList.remove ('pk_inact'); + } + + if (e === 1) { + if (wavepoint_visible) + { + wavepoint.style.display = 'none'; + wavepoint_visible = false; + } + } else { + + if (!wavepoint_visible) + { + wavepoint.style.display = 'block'; + var perc = app.engine.wavesurfer.getCurrentTime() / app.engine.wavesurfer.getDuration (); + // wavepoint.style.left = ((perc * 100).toFixed(2)/1) + '%'; + wavepoint.style.left = ((perc * 10000)>>0)/100 + '%'; + wavepoint_visible = true; + } + } + + // get zoom value and left... + if ((100/e) > 99) + { + wavedrag_width = 100; + wavedrag_style.width = '100%'; + wavedrag_style.left = '0%'; + //wavedrag_style.transform = 'translate(0,0)'; + wavedrag.classList.add ('pk_inact'); + } + else + { + wavedrag_width = (100/e); + wavedrag_style.width = wavedrag_width + '%'; + wavedrag_style.left = o + '%'; + //wavedrag_style.transform = 'translate(' + (e * o) + '%,0)'; + wavedrag.classList.remove ('pk_inact'); + } + }); + UI.listenFor ('DidCursorCenter', function( val, zoom ) { + + requestAnimationFrame(function () { + wavedrag_style.left = (val * 100) + '%'; + //wavedrag_style.transform = 'translate(' + (val * zoom * 100) + '%,0)'; + }); + }); + + var drag_mode = 0; + var startingX = 0; + var waveScrollMouseMove = function( e ) { + e.stopPropagation(); e.preventDefault(); + + var clx = e.clientX; + + if (e.touches) { + if (e.touches.length > 1) return ; + + clx = e.touches[0].clientX; + } + + var diff = -startingX + clx; + if (drag_mode === 0) + UI.fireEvent ('RequestPan', diff, 1); + else if (drag_mode === -1) + { + UI.fireEvent ('RequestZoom', diff, -1); + } + else if (drag_mode === 1) + { + UI.fireEvent ('RequestZoom', diff, 1); + } + + startingX = clx; + }, + waveScrollMouseUp = function ( e ) { + if (e.touches && e.touches.length > 1) return ; + + PKAudioEditor.engine.wavesurfer.Interacting &= ~(1 << 1); + e.stopPropagation();e.preventDefault(); + drag_mode = 0; + temp = window.performance.now(); + + wavedrag.classList.remove ('pk_drag'); + + document.removeEventListener('mousemove', waveScrollMouseMove); + document.removeEventListener('mouseup', waveScrollMouseUp); + + document.removeEventListener('touchmove', waveScrollMouseMove, {passive:false}); + document.removeEventListener('touchend', waveScrollMouseUp); + }; + + var mdown = function ( e ) { + if (!PKAudioEditor.engine.is_ready) return ; + + if (e.target === wavedrag) { + drag_mode = 0; + } else if ( e.target === wavedrag_left) { + drag_mode = -1; + } else if ( e.target === wavedrag_right) { + drag_mode = 1; + } + + wavedrag.className += ' pk_drag'; + + startingX = e.clientX; + PKAudioEditor.engine.wavesurfer.Interacting |= (1 << 1); + + if (e.is_touch) + { + document.addEventListener ('touchmove', waveScrollMouseMove, {passive:false}); + document.addEventListener ('touchend', waveScrollMouseUp, false); + } + else + { + document.addEventListener ('mousemove', waveScrollMouseMove, false); + document.addEventListener ('mouseup', waveScrollMouseUp, false); + } + }; + + wavedrag.addEventListener ('mousedown', mdown, false); + + if ('ontouchstart' in window) { + wavedrag.addEventListener ('touchstart', function ( e ) { + e.preventDefault (); + e.stopPropagation (); + + if (e.touches.length > 1) { + return ; + } + + var ev = { + is_touch : true, + target : wavedrag, + clientX: e.touches[0].clientX + }; + mdown ( ev ); + }, false); + } + + + this.volumeGauge = d.createElement( 'div' ); + this.volumeGauge2 = d.createElement( 'div' ); + + this.volumeGaugeInner = d.createElement( 'div' ); + this.volumeGaugeInner2 = d.createElement( 'div' ); + this.volumeGaugePeaker = d.createElement( 'div' ); + this.volumeGaugePeaker2 = d.createElement( 'div' ); + + var volume_parent = d.createElement('div'); + + this.volumeGauge.className = 'pk_volpar'; + this.volumeGauge2.className = 'pk_volpar'; + this.volumeGaugeInner.className = 'pk_vol'; + this.volumeGaugeInner2.className = 'pk_vol'; + this.volumeGaugePeaker.className = 'pk_peaker'; + this.volumeGaugePeaker2.className = 'pk_peaker'; + + this.volumeGauge.appendChild ( this.volumeGaugeInner ); + this.volumeGauge.appendChild( this.volumeGaugePeaker ); + + this.volumeGauge2.appendChild ( this.volumeGaugeInner2 ); + this.volumeGauge2.appendChild( this.volumeGaugePeaker2 ); + + var markers = d.createElement('div'); + markers.className = 'pk_markers pk_noselect'; + + var str = '-Inf'; + for (var i = 35; i >= 0; --i) + { + str += '' + -(i*2) + ''; + } + markers.innerHTML = str; + + volume_parent.appendChild( this.volumeGauge ); + volume_parent.appendChild( this.volumeGauge2 ); + volume_parent.appendChild( markers ); + + volume_parent.onclick = function() { + q.volumeGaugePeaker.className = 'pk_peaker'; + q.volumeGaugePeaker2.className = 'pk_peaker'; + }; + + footer.appendChild( volume_parent ); + + // change temp message, it's pretty ugly #### TODO + var ttmp = d.createElement('div'); + ttmp.className = 'pk_tmpMsg'; + ttmp.innerHTML = 'Drag n drop an Audio File in this window, or click ' + + 'here to use a sample'; + main_audio_view.appendChild( ttmp ); + + var ttmp2 = d.createElement('div'); + ttmp2.className = 'pk_tmpMsg2'; + ttmp2.innerHTML = 'Please Wait...
' + + '
0%' + + '
'; + + d.body.appendChild( ttmp2 ); + UI.loaderEl = ttmp2; + + UI.listenFor ('WillDownloadFile', function() { + UI.loaderEl.classList.add ('pk_act'); + UI.loaderEl.getElementsByTagName('span')[1].style.display = 'none'; + }); + UI.listenFor ('DidDownloadFile', function() { + UI.loaderEl.classList.remove ('pk_act'); + }); + UI.listenFor ('DidProgressModal', function ( val ) { + UI.loaderEl.getElementsByTagName('span')[1].style.display = 'block'; + UI.loaderEl.getElementsByTagName('span')[1].textContent = val + '%'; + }); + } + + + function _makeUIToolbar (UI) { + var container = d.createElement ( 'div' ); + container.className = 'pk_tbc'; + + var toolbar = d.createElement ( 'div' ); + toolbar.className = 'pk_tb pk_noselect'; + + var btn_groups = d.createElement( 'div' ); + btn_groups.className = 'pk_btngroup'; + + var transport = d.createElement( 'div' ); + transport.className = 'pk_transport'; + + // play button + var btn_stop = d.createElement ('button'); + btn_stop.setAttribute ('tabIndex', -1); + btn_stop.innerHTML = 'Stop Playback (Space)'; + btn_stop.className = 'pk_btn pk_stop icon-stop2'; + btn_stop.onclick = function() { + UI.fireEvent('RequestStop'); + }; + transport.appendChild ( btn_stop ); + + var btn_play = d.createElement ('button'); + btn_play.setAttribute ('tabIndex', -1); + btn_play.className = 'pk_btn pk_play icon-play3'; + btn_play.innerHTML = 'Play (Space)'; + transport.appendChild ( btn_play ); + btn_play.onclick = function() { + UI.fireEvent('RequestPlay'); + this.blur(); + }; + UI.listenFor ('DidStopPlay', function(){ + btn_play.classList.remove ('pk_act'); + }); + UI.listenFor ('DidPlay', function(){ + btn_play.classList.add ('pk_act'); + }); + + var btn_pause = d.createElement ('button'); + btn_pause.setAttribute('tabIndex', -1); + btn_pause.className = 'pk_btn pk_pause icon-pause2'; + btn_pause.innerHTML = 'Pause (Shift+Space)'; + transport.appendChild ( btn_pause ); + btn_pause.onclick = function() { + UI.fireEvent('RequestPause'); + this.blur(); + }; + + var btn_loop = d.createElement ('button'); + btn_loop.setAttribute('tabIndex', -1); + btn_loop.className = 'pk_btn pk_loop icon-loop'; + btn_loop.innerHTML = 'Toggle Loop (L)'; + transport.appendChild ( btn_loop ); + btn_loop.onclick = function() { + UI.fireEvent('RequestSetLoop'); + this.blur(); + }; + UI.listenFor('DidSetLoop', function( val ) { + val ? btn_loop.classList.add('pk_act') : + btn_loop.classList.remove('pk_act'); + }); + + var btn_back_jump = d.createElement ('button'); + btn_back_jump.setAttribute('tabIndex', -1); + btn_back_jump.className = 'pk_btn pk_back_jump icon-backward2'; + btn_back_jump.innerHTML = 'Seek (left arrow)'; + transport.appendChild ( btn_back_jump ); + + /////////////////////////////////////////////////////////// + // REWING / BACK BTN + var btn_back_focus = false; + var btn_back_tm = null; + btn_back_jump.onclick = function() { + + if (!btn_back_focus) + { + if (btn_back_tm) { + clearTimeout(btn_back_tm); + btn_back_tm = null; + } + + var big_step = PKAudioEditor.engine.wavesurfer.getDuration () / 20; + var zoom = PKAudioEditor.engine.wavesurfer.ZoomFactor; + big_step /= ((zoom/2)+0.5); + if (big_step > 1) big_step = big_step << 0; + + UI.fireEvent ('RequestSkipBack', big_step); + } + + this.blur(); + btn_back_focus = false; + }; + + btn_back_jump.onmouseleave = function () { + if (btn_back_tm) { + clearTimeout(btn_back_tm); + btn_back_tm = null; + } + this.blur(); + }; + + btn_back_jump.onfocus = function() { + var btn = this; + btn_back_focus = false; + + var step = function ( num, count ) { + if (document.activeElement === btn) + { + btn_back_focus = true; + + UI.fireEvent ('RequestSkipBack', num); + + var block = 4450; + + var middle_step = PKAudioEditor.engine.wavesurfer.getDuration () / block; + var zoom = PKAudioEditor.engine.wavesurfer.ZoomFactor; + middle_step /= zoom; + + if (count < 12) { + middle_step = 0; + } + + setTimeout(function() { + step (num + middle_step, ++count); + },40); + } + }; + btn_back_tm = setTimeout(function(){ + + var small = PKAudioEditor.engine.wavesurfer.getDuration () / 2000; + var zoom = PKAudioEditor.engine.wavesurfer.ZoomFactor; + small /= zoom; + + if (small < 0.01) { + small = 0.01; + } + + step (small, 0); + },390); + }; + //////////////////////// + + var btn_front_jump = d.createElement ('button'); + btn_front_jump.setAttribute('tabIndex', -1); + btn_front_jump.className = 'pk_btn pk_front_jump icon-forward3'; + btn_front_jump.innerHTML = 'Seek (right arrow)'; + transport.appendChild ( btn_front_jump ); + + var btn_frnt_focus = false; + var btn_frnt_tm = null; + btn_front_jump.onclick = function() { + if (!btn_frnt_focus) + { + if (btn_frnt_tm) { + clearTimeout(btn_frnt_tm); + btn_frnt_tm = null; + } + + var big_step = PKAudioEditor.engine.wavesurfer.getDuration () / 20; + var zoom = PKAudioEditor.engine.wavesurfer.ZoomFactor; + big_step /= ((zoom/2)+0.5); + if (big_step > 1) big_step = big_step << 0; + + UI.fireEvent ('RequestSkipFront', big_step); + } + + this.blur(); + btn_frnt_focus = false; + }; + btn_front_jump.onmouseleave = function () { + if (btn_frnt_tm) { + clearTimeout(btn_frnt_tm); + btn_frnt_tm = null; + } + this.blur(); + }; + btn_front_jump.onfocus = function() { + var btn = this; + btn_frnt_focus = false; + + var step = function ( num, count ) { + if (document.activeElement === btn) + { + btn_frnt_focus = true; + + UI.fireEvent ('RequestSkipFront', num); + + var block = 4450; + + var middle_step = PKAudioEditor.engine.wavesurfer.getDuration () / block; + var zoom = PKAudioEditor.engine.wavesurfer.ZoomFactor; + middle_step /= zoom; + + if (count < 12) { + middle_step = 0; + } + + setTimeout(function() { + step (num + middle_step, ++count); + },40); + } + }; + btn_frnt_tm = setTimeout(function(){ + + var small = PKAudioEditor.engine.wavesurfer.getDuration () / 2000; + var zoom = PKAudioEditor.engine.wavesurfer.ZoomFactor; + small /= zoom; + + if (small < 0.01) { + small = 0.01; + } + + step (small, 0); + },390); + }; + //////////////////////// + + + var k_arr_bck_time = 0; + var k_arr_bck_mult = 1; + var k_arr_bck_skip_frames = 4; + UI.KeyHandler.addCallback ('KeyArrowBack', function ( key, c, ev ) { + if (UI.InteractionHandler.on || !PKAudioEditor.engine.is_ready) return ; + + var time = ev.timeStamp; + var diff = time - k_arr_bck_time; + + if (diff > 158) { + k_arr_bck_mult = 1; + k_arr_bck_skip_frames = 4; + } else { + if (--k_arr_bck_skip_frames < 0 && k_arr_bck_mult < 6.0) + k_arr_bck_mult += 0.05; + } + + k_arr_bck_time = time; + + // get zoom factor + var jump = 0.5; + var zoom = PKAudioEditor.engine.wavesurfer.ZoomFactor; + var total_dur = PKAudioEditor.engine.wavesurfer.getDuration (); + + jump = Math.max(total_dur / 200, 0.05); + jump /= zoom; + jump *= k_arr_bck_mult; + + UI.fireEvent( 'RequestSkipBack', jump ); + }, [37]); + + var k_arr_frnt_time = 0; + var k_arr_frnt_mult = 1; + var k_arr_frnt_skip_frames = 4; + UI.KeyHandler.addCallback ('KeyArrowFront', function ( key, c, ev ) { + if (UI.InteractionHandler.on || !PKAudioEditor.engine.is_ready) return ; + + var time = ev.timeStamp; + var diff = time - k_arr_frnt_time; + + if (diff > 158) { + k_arr_frnt_mult = 1; + k_arr_frnt_skip_frames = 4; + } else { + if (--k_arr_frnt_skip_frames < 0 && k_arr_frnt_mult < 6.0) + k_arr_frnt_mult += 0.05; + } + + k_arr_frnt_time = time; + + var jump = 0.5; + var zoom = PKAudioEditor.engine.wavesurfer.ZoomFactor; + var total_dur = PKAudioEditor.engine.wavesurfer.getDuration (); + + jump = Math.max(total_dur / 200, 0.05); + + jump /= zoom; + jump *= k_arr_frnt_mult; + + UI.fireEvent( 'RequestSkipFront', jump ); + }, [39]); + UI.KeyHandler.addCallback ('KeyShiftArrowBack', function ( key ) { + if (UI.InteractionHandler.on || !PKAudioEditor.engine.is_ready) return ; + + var region = PKAudioEditor.engine.wavesurfer.regions.list[0]; + if (region) + { + var pos = PKAudioEditor.engine.wavesurfer.ActiveMarker; + var total_dur = PKAudioEditor.engine.wavesurfer.getDuration (); + + var durr = region.end / total_dur; + + if (pos > (durr + 0.004)) + { + UI.fireEvent( 'RequestSeekTo', durr - 0.0001 ); + return ; + } + + durr = region.start / total_dur; + + if (pos > (durr + 0.004)) + { + UI.fireEvent( 'RequestSeekTo', durr ); + return ; + } + } + + UI.fireEvent( 'RequestSeekTo', 0 ); + }, [16, 37]); + UI.KeyHandler.addCallback ('KeyShiftArrowFront', function ( key ) { + if (UI.InteractionHandler.on || !PKAudioEditor.engine.is_ready) return ; + + // if region skip to the region + var region = PKAudioEditor.engine.wavesurfer.regions.list[0]; + if (region) + { + var pos = PKAudioEditor.engine.wavesurfer.ActiveMarker; + var total_dur = PKAudioEditor.engine.wavesurfer.getDuration (); + + var durr = region.start / total_dur; + + if (pos < (durr - 0.004)) + { + UI.fireEvent( 'RequestSeekTo', durr ); + return ; + } + + durr = region.end / total_dur; + + if (pos < (durr - 0.004)) + { + UI.fireEvent( 'RequestSeekTo', durr - 0.0001 ); + return ; + } + } + + UI.fireEvent( 'RequestSeekTo', 0.994 ); + }, [16, 39]); + UI.KeyHandler.addCallback ('killctx', function ( e ) { + var event = new Event ('killCTX', {bubbles: true}); + document.body.dispatchEvent (event); + }, [27]); + + var btn_back_total = d.createElement ('button'); + btn_back_total.setAttribute('tabIndex', -1); + btn_back_total.className = 'pk_btn icon-previous2'; + btn_back_total.innerHTML = 'Seek Start (Shift + left arrow)'; + transport.appendChild ( btn_back_total ); + btn_back_total.onclick = function() { + UI.fireEvent( 'RequestRegionClear'); + UI.fireEvent( 'RequestSeekTo', 0 ); + this.blur(); + }; + + var btn_front_total = d.createElement ('button'); + btn_front_total.setAttribute('tabIndex', -1); + btn_front_total.className = 'pk_btn icon-next2'; + btn_front_total.innerHTML = 'Seek End (Shift + right arrow)'; + btn_front_total.onclick = function() { + UI.fireEvent( 'RequestRegionClear'); + UI.fireEvent( 'RequestSeekTo', 0.996); + this.blur(); + }; + transport.appendChild ( btn_front_total ); + + + var btn_rec = d.createElement ('button'); + btn_rec.setAttribute('tabIndex', -1); + btn_rec.className = 'pk_btn icon-rec'; + btn_rec.innerHTML = 'Record (R)'; + btn_rec.onclick = function() { + if (this.getAttribute('disabled') === 'disabled') { + this.blur (); return ; + } + + UI.fireEvent('RequestActionRecordToggle'); + this.blur(); + }; + + UI.listenFor ('ErrorRec', function() { + btn_rec.style.opacity = 0.6; + btn_rec.setAttribute("disabled", "disabled"); + }); + + transport.appendChild ( btn_rec ); + UI.KeyHandler.addCallback ('KeyRecR', function( k ) { + if (UI.InteractionHandler.on) return ; + btn_rec.click (); + }, [82]); + + UI.listenFor ('DidActionRecordStart', function () { + btn_rec.classList.add ('pk_act'); + }); + UI.listenFor ('DidActionRecordStop', function () { + btn_rec.classList.remove ('pk_act'); + }); + + UI.KeyHandler.addCallback ('KeyTab', function ( key ) { + if (UI.InteractionHandler.on || !PKAudioEditor.engine.is_ready) return ; + + UI.fireEvent ('RequestViewCenterToCursor'); + }, [9]); + + var is_chrome = !!window.chrome; + var timing = d.createElement( 'div' ); + timing.className = 'pk_timecontainer'; + + var timingspan = d.createElement( 'span' ); + + if (!is_chrome) + { + timingspan.textContent = '00:00:000'; + timingspan.className = 'pk_timing'; + timing.appendChild( timingspan ); + } + + ///// + var pk_timingcnv = d.createElement( 'canvas' ); + pk_timingcnv.className = 'pk_timingcnv'; + pk_timingcnv.width = 150; + pk_timingcnv.height = 40; + var pk_timingnum = '00:00:000'; + var pk_timingctx = pk_timingcnv.getContext('2d', {alpha:false}); + var timing_caches = {}; + + if (is_chrome) + { + timing.appendChild( pk_timingcnv ); + pk_timingctx.fillStyle = "#000"; + pk_timingctx.fillRect(0, 0, 150, 40); + + for (var ii = 0; ii < 11; ++ii) + { + var curr_cache = d.createElement('canvas'); + curr_cache.width = 18; + curr_cache.height = 26; + var curr_ctx = curr_cache.getContext('2d', {alpha:false}); + curr_ctx.font = "29px Helvetica, Arial, sans-serif"; + curr_ctx.textAlign = "center"; + curr_ctx.fillStyle = "#000"; + curr_ctx.fillRect(0, 0, 18, 26); + curr_ctx.fillStyle = "#fff"; + curr_ctx.textBaseline = 'middle'; + + if (ii === 10) { + curr_ctx.fillText (':', 8, 14); + timing_caches[':'] = curr_cache; + } + else { + curr_ctx.fillText (ii + '', 9, 14); + timing_caches[ii+''] = curr_cache; + } + // timing_caches.push (curr_cache); + // document.body.appendChild( curr_cache ); + } + + (function (pk_timingctx, timing_caches){ + var ttm = '00:00:000'; + for (var jk = 0; jk < ttm.length; ++jk) + { + pk_timingctx.drawImage (timing_caches[ttm[jk]], jk * 16, 10); + } + })(pk_timingctx, timing_caches); + } + ///// + + + var total_duration = d.createElement( 'span' ); + total_duration.textContent = '00:00:000'; + total_duration.className = 'pk_total_dur'; + timing.appendChild( total_duration ); + + var hover_duration = d.createElement( 'span' ); + hover_duration.textContent = '00:00:000'; + hover_duration.className = 'pk_hover_dur'; + timing.appendChild( hover_duration ); + + setTimeout(function () { + UI.listenFor ('DidZoom', function (v, f) { + // do something smarter for f (event) #### + if (f) + hover_duration.textContent = formatTime ( + PKAudioEditor.engine.wavesurfer.drawer.handleEvent(f) * + PKAudioEditor.engine.wavesurfer.VisibleDuration + + PKAudioEditor.engine.wavesurfer.LeftProgress ); + }); + + var old_refresh = 0; + + var avv = d.getElementsByClassName('pk_av')[0]; + avv.addEventListener ('mousemove', function ( e ) { + // re-run the mousemove fam on zoom based on the pointer position) + + // throttle this as well #### violation + var new_refresh = e.timeStamp; + + if (new_refresh - old_refresh < 58) { + return ; + } + + old_refresh = new_refresh; + + hover_duration.textContent = formatTime ( + PKAudioEditor.engine.wavesurfer.drawer.handleEvent( e ) * + PKAudioEditor.engine.wavesurfer.VisibleDuration + + PKAudioEditor.engine.wavesurfer.LeftProgress ); + }, false); + + + var main_context = PKAudioEditor._deps.ContextMenu ( avv ); + + main_context.addOption ('Select Visible View', function( e,x,i ) { + UI.fireEvent ('RequestRegionSet'); + }, false ); + + main_context.addOption ('Reset Zoom', function( e ) { + UI.fireEvent ('RequestZoomUI', 0); + }, false ); + + main_context.addOption ('Set Volume/Gain', function( e ) { + UI.fireEvent ('RequestFXUI_Gain'); + }, false ); + + main_context.addOption ('Copy', function( e ) { + var region = PKAudioEditor.engine.wavesurfer.regions.list[0]; + if (!region) return ; + + UI.fireEvent( 'RequestActionCopy'); + }, false ); + main_context.addOption ('Paste', function( e ) { + if (!copable) return ; + UI.fireEvent( 'RequestActionPaste'); + }, false ); + main_context.addOption ('Cut', function( e ) { + var region = PKAudioEditor.engine.wavesurfer.regions.list[0]; + if (!region) return ; + + UI.fireEvent( 'RequestActionCut', 1); + }, false ); + main_context.addOption ('Insert Silence', function( e ) { + UI.fireEvent ('RequestFXUI_Silence', 0); // #### call effect + }, false ); + // --- + + + var copable = false; + UI.listenFor ('DidSetClipboard', function ( val ) { + if (val) + copable = true; + else + copable = false; + }); + + main_context.onOpen = function ( menu, div ) { + var divs = div.childNodes; + if (!copable) divs[4].className += ' pk_inact'; + + UI.fireEvent ('RequestPause'); + + var region = PKAudioEditor.engine.wavesurfer.regions.list[0]; + if (region) return ; + + divs[3].className += ' pk_inact'; + divs[5].className += ' pk_inact'; + }; + + }, 1000); + + UI.listenFor ('DidUpdateLen', function( val ) { + total_duration.textContent = formatTime (val); + }); + + function formatTime( time ) { + var time_s = time >> 0; + var miliseconds = time - time_s; + + if (time_s < 10) + { + if (time === 0) return '00:00:000'; + time_s = '00:0' + time_s; + } + else if (time_s < 60) + { + time_s = '00:' + time_s; + } + else + { + var m = (time_s / 60) >> 0; + var s = (time_s % 60); + time_s = ((m<10)?'0':'') + m + ':' + (s < 10 ? '0'+s : s); + } + + if (miliseconds < 0.1) + { + return time_s + ':0' + (miliseconds < 0.01 ? '0' : '') + ((miliseconds*1000)>>0); + } + + return time_s + ':' + ((miliseconds*1000)>>0); // (miliseconds+'').substr(2, 3); + } + UI.formatTime = formatTime; + + var volume1 = 0; + var volume2 = 0; + var old_refresh = 0; + var wvpnt = document.querySelector('.pk_wavepoint'); + + UI.listenFor ('DidAudioProcess', function( val ) { + + var time = val[0]; + var loudness = val[1]; + + var new_refresh = val[2] || w.performance.now (); + + if (new_refresh - old_refresh < 50) { + return ; + } + + old_refresh = new_refresh; + + if (time > -1) + { + if (!is_chrome) + { + timingspan.textContent = formatTime (time); + } + else + { + var ttm = formatTime (time); + var exit = false; + + for (var jk = 0; jk < ttm.length; ++jk) + { + if (!exit) + { + if (ttm[jk] === pk_timingnum[jk]) { + continue; + } + else { + // pk_timingctx.clearRect ((jk * 16), 10, (9 - jk) * 16, 35); + exit = true; + } + } + + pk_timingctx.drawImage (timing_caches[ttm[jk]], jk * 16, 10); + } + pk_timingnum = ttm; + } + + + if (PKAudioEditor.engine.wavesurfer.ZoomFactor > 1) + { + var perc = time / PKAudioEditor.engine.wavesurfer.getDuration (); + + if (!wvpnt) wvpnt = document.querySelector('.pk_wavepoint'); + wvpnt.style.left = ((perc * 10000)>>0)/100 + '%'; + // wvpnt.style.left = ((perc * 100).toFixed(2)/1) + '%'; + } + } + + if (!loudness) + { + UI.footer.volumeGaugePeaker.className = 'pk_peaker'; + UI.footer.volumeGaugePeaker2.className = 'pk_peaker'; + + UI.footer.volumeGaugeInner.style.transform = 'translate3d(0,0,0)'; + UI.footer.volumeGaugeInner2.style.transform = 'translate3d(0,0,0)'; + // UI.footer.volumeGaugeInner.style.width = '100%'; + // UI.footer.volumeGaugeInner2.style.width = '100%'; + } + else if (loudness[0] > 0) { + UI.footer.volumeGaugePeaker.className = 'pk_peaker pk_act'; + + UI.footer.volumeGaugeInner.style.transform = 'translate3d(100%,0,0)'; + // UI.footer.volumeGaugeInner.style.width = '0%'; + volume1 = 100; + + UI.footer.volumeGaugePeaker.setAttribute ('title', 'Peak at ' + PKAudioEditor.engine.wavesurfer.getCurrentTime().toFixed(2) ); + if (loudness[1] > 0) { + UI.footer.volumeGaugePeaker2.className = 'pk_peaker pk_act'; + + UI.footer.volumeGaugeInner2.style.transform = 'translate3d(100%,0,0)'; + // UI.footer.volumeGaugeInner2.style.width = '0%'; + volume2 = 100; + + UI.footer.volumeGaugePeaker2.setAttribute ('title', 'Peak at ' + PKAudioEditor.engine.wavesurfer.getCurrentTime().toFixed(2) ); + } + } + else if (loudness[1] > 0) { + UI.footer.volumeGaugePeaker2.className = 'pk_peaker pk_act'; + + UI.footer.volumeGaugeInner2.style.transform = 'translate3d(100%,0,0)'; + // UI.footer.volumeGaugeInner2.style.width = '0%'; + volume2 = 100; + + UI.footer.volumeGaugePeaker2.setAttribute ('title', 'Peak at ' + PKAudioEditor.engine.wavesurfer.getCurrentTime().toFixed(2) ); + } + else + { + var tmp = (100 + loudness[0]); + if (tmp < -100) volume1 = 0; // tmp = -100; + else + { + volume1 = volume1 + (tmp - volume1)/4; + if (isNaN (volume1)) volume1 = 0; + } + + tmp = (100 + loudness[1]); + if (tmp < -100) volume2 = 0; //tmp = -100; + else + { + volume2 = volume2 + (tmp - volume2)/4; + if (isNaN (volume2)) volume2 = 0; + } + + UI.footer.volumeGaugeInner.style.transform = 'translate3d(' + volume1 + '%,0,0)'; + UI.footer.volumeGaugeInner2.style.transform = 'translate3d(' + volume2 + '%,0,0)'; + // UI.footer.volumeGaugeInner.style.width = (100 - volume1) + '%'; + // UI.footer.volumeGaugeInner2.style.width = (100 - volume2) + '%'; + } + }); + + + var actions = d.createElement( 'div' ); + actions.className = 'pk_ctns'; + + var copy_btn = d.createElement ('button'); + copy_btn.setAttribute('tabIndex', -1); + copy_btn.className = 'pk_btn icon-files-empty pk_inact'; + copy_btn.innerHTML = 'Copy Selection (Shift + C)'; + actions.appendChild ( copy_btn ); + + copy_btn.onclick = function() { + UI.fireEvent( 'RequestActionCopy'); + this.blur(); + }; + + UI.listenFor ('DidSetClipboard', function ( val ) { + if (val) + paste_btn.classList.remove ('pk_inact'); + else + paste_btn.classList.add ('pk_inact'); + }); + + var paste_btn = d.createElement ('button'); + paste_btn.setAttribute('focusable', 'false'); + paste_btn.className = 'pk_btn icon-file-text2 pk_inact'; + paste_btn.innerHTML = 'Paste Selection (Shift + V)'; + actions.appendChild ( paste_btn ); + + paste_btn.onclick = function() { + UI.fireEvent( 'RequestActionPaste'); + this.blur(); + }; + + var cut_btn = d.createElement ('button'); + cut_btn.setAttribute('tabIndex', -1); + cut_btn.className = 'pk_btn icon-scissors pk_inact'; + cut_btn.innerHTML = 'Cut Selection (Shift + X)'; + actions.appendChild ( cut_btn ); + + cut_btn.onclick = function() { + UI.fireEvent( 'RequestActionCut', 1); + this.blur(); + }; + + var silence_btn = d.createElement ('button'); + silence_btn.setAttribute('tabIndex', -1); + silence_btn.className = 'pk_btn icon-silence'; + silence_btn.innerHTML = 'Insert Silence (Shift + N)'; + actions.appendChild ( silence_btn ); + + UI.KeyHandler.addCallback ('KeyShiftN', function( k ) { + if (UI.InteractionHandler.on) return ; + + silence_btn.click (); + },[16, 78]); + + silence_btn.onclick = function() { + UI.fireEvent( 'RequestFXUI_Silence'); + this.blur(); + }; + + + + var selection = d.createElement( 'div' ); + selection.className = 'pk_selection'; + selection.innerHTML = '
' + + 'Selection:' + + '
Start:-
' + + '
End:-
' + + '
Duration:-
' + + '
'; + + var btn_clear_selection = d.createElement ('button'); + btn_clear_selection.setAttribute('tabIndex', -1); + btn_clear_selection.className = 'pk_btn icon-clearsel pk_inact'; + btn_clear_selection.innerHTML = 'Clear Selection (Q key)'; + + var sel_spans = selection.getElementsByClassName('pk_dat'); + UI.listenFor ('DidCreateRegion', function ( region ) { + copy_btn.classList.remove ('pk_inact'); + cut_btn.classList.remove ('pk_inact'); + btn_clear_selection.classList.remove ('pk_inact'); + + if (region) + { + if (!sel_spans[0]) sel_spans = document.querySelectorAll('.pk_sellist .pk_dat'); + sel_spans[0].textContent = region.start.toFixed(3); + sel_spans[1].textContent = region.end.toFixed(3); + sel_spans[2].textContent = (region.end - region.start).toFixed(3); + } + }); + UI.listenFor ('DidDestroyRegion', function () { + copy_btn.classList.add ('pk_inact'); + cut_btn.classList.add ('pk_inact'); + btn_clear_selection.classList.add ('pk_inact'); + + if (!sel_spans[0]) sel_spans = document.querySelectorAll('.pk_sellist .pk_dat'); + sel_spans[0].textContent = '-'; + sel_spans[1].textContent = '-'; + sel_spans[2].textContent = '-'; + }); + + btn_clear_selection.onclick = function () { + UI.fireEvent( 'RequestRegionClear'); + this.blur (); + }; + selection.appendChild ( btn_clear_selection ); + + toolbar.appendChild ( timing ); + + + UI.listenFor ('DidChanToggle', function ( chan, val ) { + var region = PKAudioEditor.engine.wavesurfer.regions.list[0]; + if (!region) return ; + + if (val === 1) { + region.element.style.top = '0'; + region.element.style.height = '100%'; + return ; + } + + if (chan === 0) { + region.element.style.top = '50%'; + region.element.style.height = '50%'; + return ; + } + + if (chan === 1) { + region.element.style.top = '0'; + region.element.style.height = '50%'; + } + // + }); + + // end + toolbar.appendChild ( btn_groups ); + btn_groups.appendChild ( transport ); + btn_groups.appendChild ( actions ); + toolbar.appendChild ( selection ); + + container.appendChild ( toolbar ); + + UI.el.appendChild ( container ); + + dragNDrop( d.getElementById('app'), 'pk_overlay', function ( e ) { + PKAudioEditor.engine.LoadArrayBuffer ( new Blob([e]) ); + }, 'arrayBuffer' ); + + // - + }; + + function _makeMobileScroll (UI) { + + var getFactor = function () { + var screen_h = window.screen.height; + var screen_w = window.screen.width; + + var iw = window.innerWidth; + var ih = window.innerHeight; + + var bars_visible = false; + var ratio = 0; + + if (window.orientation === 0) { + ratio = ih / screen_h; + } + else if (window.orientation === 90 || window.orientation === -90) { + ratio = ih / screen_w; + } + if (ratio < 0.8) bars_visible = true; + + return (bars_visible); + }; + + var ex = -1; + var ey = -1; + + var allow = false; + // var first = false; + d.body.addEventListener ('touchstart', function( e ) { + ex = e.touches[0].pageX; + ey = e.touches[0].pageY; + + // first = true; + allow = false; + }); + + d.body.addEventListener ('touchend', function( e ) { + ex = -1; + ey = -1; + + // first = false; + allow = false; + }); + + d.body.addEventListener ('touchmove', function( e ) { + if (e.target.tagName === 'INPUT') return ; + if (allow) return ; + + var ny = e.touches[0].pageY; + var nx = e.touches[0].pageX; + var direction = ey - ny; + var direction2 = ex - nx; + + // if (first) { + // first = false; + // } + + if ( direction === 0 || (Math.abs (direction) < 3 && Math.abs (direction2) > 3 ) || (Math.abs (direction) < 6 && Math.abs (direction2) > 10 ) ) { + ey = ny; + ex = nx; + allow = true; + + return ; + } + + ey = ny; + ex = nx; + + var xx = document.getElementsByClassName ('pk_modal_back'); + + if (xx[0]) + { + xx = xx[0]; + if ( xx.scrollHeight > window.innerHeight ) + { + var scrolled = xx.scrollTop; + + if (direction > 0) + { + var modal_h = document.getElementsByClassName ('pk_modal')[0].clientHeight; + + if ((modal_h - scrolled) < (window.innerHeight - 80)) + { + e.preventDefault (); + } + } + else + { + if (scrolled <= 0) + { + e.preventDefault (); + } + } + + allow = true; + return ; + } + else + { + e.preventDefault (); + + allow = true; + return ; + } + } + + + if (!getFactor ()) { + e.preventDefault (); + allow = true; + } + + }, {passive:false}); + }; + // --- + + PKAE._deps.ui = PKUI; + +})( window, document, PKAudioEditor ); \ No newline at end of file diff --git a/audiomass-editor/src/wav.js b/audiomass-editor/src/wav.js new file mode 100644 index 0000000..0ad9419 --- /dev/null +++ b/audiomass-editor/src/wav.js @@ -0,0 +1,109 @@ +function interleave(inputL, inputR) { + var length = inputL.length + inputR.length; + var result = new Int16Array(length); + + var index = 0, + inputIndex = 0; + + while (index < length) { + result[index++] = inputL[inputIndex]; + result[index++] = inputR[inputIndex]; + ++inputIndex; + } + return result; +} + +function floatTo16BitPCM(output, offset, input) { + for (var i = 0; i < input.length; i++, offset += 2) { + output.setInt16(offset, input[i], true); + } +} + +function writeString(view, offset, string) { + for (var i = 0; i < string.length; i++) { + view.setUint8(offset + i, string.charCodeAt(i)); + } +} + +function encodeWAV(samples, numChannels, sampleRate) { + var buffer = new ArrayBuffer(44 + samples.length * 2); + var view = new DataView(buffer); + + /* RIFF identifier */ + writeString(view, 0, 'RIFF'); + /* RIFF chunk length */ + view.setUint32(4, 36 + samples.length * 2, true); + /* RIFF type */ + writeString(view, 8, 'WAVE'); + /* format chunk identifier */ + writeString(view, 12, 'fmt '); + /* format chunk length */ + view.setUint32(16, 16, true); + /* sample format (raw) */ + view.setUint16(20, 1, true); + /* channel count */ + view.setUint16(22, numChannels, true); + /* sample rate */ + view.setUint32(24, sampleRate, true); + /* byte rate (sample rate * block align) */ + view.setUint32(28, sampleRate * numChannels * 2, true); + /* block align (channel count * bytes per sample) */ + view.setUint16(32, numChannels * 2, true); + /* bits per sample */ + view.setUint16(34, 16, true); + /* data chunk identifier */ + writeString(view, 36, 'data'); + /* data chunk length */ + view.setUint32(40, samples.length * 2, true); + + floatTo16BitPCM(view, 44, samples); + + return view; +} + + + +var sample_rate = 44100; +var kbps = 128; +var channels = 1; +var mp3encoder = null; + +var samples_left = null; +var samples_right = null; +var first_buffer = true; + +onmessage = function( ev ) { + if (!ev.data) return ; + + if (ev.data.sample_rate) { + sample_rate = ev.data.sample_rate / 1; + kbps = ev.data.kbps / 1; + channels = ev.data.channels / 1; + + return ; + } + + if (first_buffer) { + samples_left = new Int16Array (ev.data, 0); + first_buffer = false; + + if (channels > 1) return ; + } + + if (ev.data && channels > 1) { + samples_right = new Int16Array (ev.data, 0); + } + + /// + var interleaved = undefined; + if (channels > 1) { + interleaved = interleave(samples_left, samples_right); + } else { + interleaved = samples_left; + } + + var dataview = encodeWAV(interleaved, channels, sample_rate); + var audioBlob = new Blob([dataview], { type: 'audio/wav' }); + + postMessage( audioBlob ); +} \ No newline at end of file diff --git a/audiomass-editor/src/welcome.js b/audiomass-editor/src/welcome.js new file mode 100755 index 0000000..e9a5206 --- /dev/null +++ b/audiomass-editor/src/welcome.js @@ -0,0 +1,71 @@ +(function ( w, d, PKAE ) { +'use strict'; + +setTimeout(function () { + + PKAudioEditor._deps.Wlc = function () { + var body_str = ''; + var body_str2 = ''; + + if (PKAE.isMobile) { + change -= 15; + body_str = 'Tips:
Please make sure your device is not in silent mode. You might need to physically flip the silent switch. '+ + ''+ + '

'; + } + else { + body_str = 'Tips:
Please keep in mind that most key shortcuts rely on the Shift + key combo. (eg Shift+Z for undo, Shift+C copy, Shift+X cut... etc )

'; + body_str2 = 'Check out the codebase on Github

'; // checkout the code on github + } + + // Welcome to AudioMass, + var md = new PKSimpleModal({ + title: 'Welcome to AudioMass', + ondestroy: function( q ) { + PKAE.ui.InteractionHandler.on = false; + PKAE.ui.KeyHandler.removeCallback ('modalTemp'); + }, + body:'
'+ + 'AudioMass is a free, open source, web-based Audio and Waveform Editor.
It runs entirely in the browser with no backend and no plugins required!'+ + '


'+ + body_str+ + 'You can load any type of audio your browser supports and perform operations such as fade in, cut, trim, change the volume, '+ + 'and apply a plethora of audio effects.

'+ + body_str2+ + '
', + setup:function( q ) { + PKAE.ui.InteractionHandler.checkAndSet ('modal'); + PKAE.ui.KeyHandler.addCallback ('modalTemp', function ( e ) { + q.Destroy (); + }, [27]); + + // ------ + var scroll = q.el_body.getElementsByTagName('div')[0]; + scroll.addEventListener ('touchstart', function(e){ + e.stopPropagation (); + }, false); + scroll.addEventListener ('touchmove', function(e){ + e.stopPropagation (); + }, false); + + // ------ + } + }); + md.Show (); + document.getElementsByClassName('pk_modal_cancel')[0].innerHTML = '      OK      '; + }; + + var change = 96; + var exists = w.localStorage && w.localStorage.getItem ('k'); + + if (!exists) { + change = 0; + w.localStorage && w.localStorage.setItem ('k', 1); + } + + if ( ((Math.random () * 100) >> 0) < change) return ; + PKAudioEditor._deps.Wlc (); + +}, 320); + +})( window, document, PKAudioEditor ); \ No newline at end of file diff --git a/components/AlbumCover.tsx b/components/AlbumCover.tsx new file mode 100644 index 0000000..3287cb1 --- /dev/null +++ b/components/AlbumCover.tsx @@ -0,0 +1,296 @@ +import React, { useMemo } from 'react'; + +interface AlbumCoverProps { + seed: string; + size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full'; + className?: string; + children?: React.ReactNode; +} + +// Seeded random number generator for consistent results +class SeededRandom { + private seed: number; + + constructor(seed: string) { + this.seed = this.hashString(seed); + } + + private hashString(str: string): number { + let hash = 0; + for (let i = 0; i < str.length; i++) { + const char = str.charCodeAt(i); + hash = ((hash << 5) - hash) + char; + hash = hash & hash; + } + return Math.abs(hash) || 1; + } + + next(): number { + this.seed = (this.seed * 1103515245 + 12345) & 0x7fffffff; + return this.seed / 0x7fffffff; + } + + range(min: number, max: number): number { + return min + this.next() * (max - min); + } + + int(min: number, max: number): number { + return Math.floor(this.range(min, max)); + } + + pick(arr: T[]): T { + return arr[this.int(0, arr.length)]; + } +} + +// Curated color palettes - music-themed combinations +const palettes = [ + // Sunset Vibes + { colors: ['#FF6B6B', '#FEC89A', '#FFD93D', '#C9184A'], bg: '#1a1a2e' }, + // Ocean Depths + { colors: ['#0077B6', '#00B4D8', '#90E0EF', '#CAF0F8'], bg: '#03045E' }, + // Forest Night + { colors: ['#2D6A4F', '#40916C', '#52B788', '#95D5B2'], bg: '#1B4332' }, + // Neon Dreams + { colors: ['#F72585', '#7209B7', '#3A0CA3', '#4CC9F0'], bg: '#10002B' }, + // Golden Hour + { colors: ['#FF9500', '#FF5400', '#FFBD00', '#FFE066'], bg: '#2D1B00' }, + // Arctic Aurora + { colors: ['#48CAE4', '#00F5D4', '#9B5DE5', '#F15BB5'], bg: '#0A0A1A' }, + // Lavender Haze + { colors: ['#E0AAFF', '#C77DFF', '#9D4EDD', '#7B2CBF'], bg: '#240046' }, + // Cherry Blossom + { colors: ['#FFCCD5', '#FFB3C1', '#FF758F', '#C9184A'], bg: '#2B0A14' }, + // Cyber Punk + { colors: ['#00FF87', '#60EFFF', '#FF00E5', '#FFE500'], bg: '#0D0D0D' }, + // Deep Space + { colors: ['#7400B8', '#5E60CE', '#4EA8DE', '#56CFE1'], bg: '#03071E' }, + // Warm Ember + { colors: ['#FFBA08', '#FAA307', '#F48C06', '#E85D04'], bg: '#370617' }, + // Cool Mint + { colors: ['#64DFDF', '#72EFDD', '#80FFDB', '#5EEAD4'], bg: '#0D3B3B' }, + // Velvet Rose + { colors: ['#9D174D', '#BE185D', '#DB2777', '#EC4899'], bg: '#1C0A14' }, + // Electric Blue + { colors: ['#0EA5E9', '#38BDF8', '#7DD3FC', '#E0F2FE'], bg: '#0C1929' }, + // Jungle Fever + { colors: ['#84CC16', '#A3E635', '#BEF264', '#ECFCCB'], bg: '#1A2E05' }, +]; + +type PatternType = 'aurora' | 'mesh' | 'orbs' | 'rays' | 'waves' | 'geometric' | 'nebula' | 'gradient' | 'rings' | 'crystal'; + +const generatePattern = (rng: SeededRandom, palette: typeof palettes[0]): React.CSSProperties => { + const patterns: PatternType[] = ['aurora', 'mesh', 'orbs', 'rays', 'waves', 'geometric', 'nebula', 'gradient', 'rings', 'crystal']; + const pattern = rng.pick(patterns); + const colors = palette.colors; + const bg = palette.bg; + + switch (pattern) { + case 'aurora': { + const angle1 = rng.int(0, 360); + const angle2 = rng.int(0, 360); + return { + background: ` + linear-gradient(${angle1}deg, ${colors[0]}00 0%, ${colors[0]}88 25%, ${colors[1]}88 50%, ${colors[2]}88 75%, ${colors[3]}00 100%), + linear-gradient(${angle2}deg, ${colors[2]}00 0%, ${colors[3]}66 30%, ${colors[0]}66 70%, ${colors[1]}00 100%), + radial-gradient(ellipse at ${rng.int(20, 80)}% ${rng.int(60, 100)}%, ${colors[1]}44 0%, transparent 50%), + linear-gradient(180deg, ${bg} 0%, ${colors[3]}22 100%) + `, + backgroundColor: bg, + }; + } + + case 'mesh': { + const points = [ + { x: rng.int(0, 40), y: rng.int(0, 40) }, + { x: rng.int(60, 100), y: rng.int(0, 40) }, + { x: rng.int(0, 40), y: rng.int(60, 100) }, + { x: rng.int(60, 100), y: rng.int(60, 100) }, + ]; + return { + background: ` + radial-gradient(at ${points[0].x}% ${points[0].y}%, ${colors[0]} 0%, transparent 50%), + radial-gradient(at ${points[1].x}% ${points[1].y}%, ${colors[1]} 0%, transparent 50%), + radial-gradient(at ${points[2].x}% ${points[2].y}%, ${colors[2]} 0%, transparent 50%), + radial-gradient(at ${points[3].x}% ${points[3].y}%, ${colors[3]} 0%, transparent 50%) + `, + backgroundColor: bg, + }; + } + + case 'orbs': { + const orbCount = rng.int(3, 6); + const orbs = Array.from({ length: orbCount }, (_, i) => { + const size = rng.int(30, 70); + const x = rng.int(10, 90); + const y = rng.int(10, 90); + const color = colors[i % colors.length]; + const blur = rng.int(20, 40); + return `radial-gradient(circle ${size}% at ${x}% ${y}%, ${color}99 0%, ${color}44 ${blur}%, transparent 70%)`; + }); + return { + background: [...orbs, `linear-gradient(135deg, ${bg} 0%, ${colors[0]}11 100%)`].join(', '), + backgroundColor: bg, + }; + } + + case 'rays': { + const centerX = rng.int(30, 70); + const centerY = rng.int(30, 70); + const rayCount = rng.int(6, 12); + const rays = Array.from({ length: rayCount }, (_, i) => { + const angle = (360 / rayCount) * i + rng.int(-10, 10); + const color = colors[i % colors.length]; + return `linear-gradient(${angle}deg, transparent 0%, transparent 45%, ${color}66 48%, ${color}66 52%, transparent 55%, transparent 100%)`; + }); + return { + background: [ + `radial-gradient(circle at ${centerX}% ${centerY}%, ${colors[0]} 0%, transparent 30%)`, + ...rays, + ].join(', '), + backgroundColor: bg, + }; + } + + case 'waves': { + const waveAngle = rng.int(0, 180); + const waveSize = rng.int(8, 20); + return { + background: ` + repeating-linear-gradient( + ${waveAngle}deg, + ${colors[0]}44 0px, + ${colors[1]}44 ${waveSize}px, + ${colors[2]}44 ${waveSize * 2}px, + ${colors[3]}44 ${waveSize * 3}px, + ${colors[0]}44 ${waveSize * 4}px + ), + radial-gradient(ellipse at 50% 0%, ${colors[0]}66 0%, transparent 70%), + radial-gradient(ellipse at 50% 100%, ${colors[2]}66 0%, transparent 70%) + `, + backgroundColor: bg, + }; + } + + case 'geometric': { + const angle = rng.int(0, 90); + return { + background: ` + conic-gradient(from ${angle}deg at 50% 50%, ${colors[0]}, ${colors[1]}, ${colors[2]}, ${colors[3]}, ${colors[0]}), + repeating-conic-gradient(from 0deg at 50% 50%, ${bg}00 0deg, ${bg}88 ${90/rng.int(2,6)}deg) + `, + backgroundBlendMode: 'overlay', + backgroundColor: bg, + }; + } + + case 'nebula': { + const x1 = rng.int(20, 80); + const y1 = rng.int(20, 80); + const x2 = rng.int(20, 80); + const y2 = rng.int(20, 80); + return { + background: ` + radial-gradient(ellipse ${rng.int(60, 100)}% ${rng.int(40, 80)}% at ${x1}% ${y1}%, ${colors[0]}88 0%, transparent 50%), + radial-gradient(ellipse ${rng.int(40, 80)}% ${rng.int(60, 100)}% at ${x2}% ${y2}%, ${colors[1]}88 0%, transparent 50%), + radial-gradient(ellipse ${rng.int(50, 90)}% ${rng.int(50, 90)}% at ${100-x1}% ${100-y1}%, ${colors[2]}66 0%, transparent 60%), + radial-gradient(ellipse ${rng.int(30, 60)}% ${rng.int(30, 60)}% at ${100-x2}% ${100-y2}%, ${colors[3]}44 0%, transparent 70%), + linear-gradient(${rng.int(0, 360)}deg, ${bg} 0%, ${colors[0]}22 50%, ${bg} 100%) + `, + backgroundColor: bg, + }; + } + + case 'gradient': { + const angle = rng.int(0, 360); + const type = rng.int(0, 3); + if (type === 0) { + return { + background: `linear-gradient(${angle}deg, ${colors[0]} 0%, ${colors[1]} 33%, ${colors[2]} 66%, ${colors[3]} 100%)`, + }; + } else if (type === 1) { + return { + background: ` + radial-gradient(circle at ${rng.int(30, 70)}% ${rng.int(30, 70)}%, ${colors[0]} 0%, ${colors[1]} 30%, ${colors[2]} 60%, ${colors[3]} 100%) + `, + }; + } else { + return { + background: ` + linear-gradient(${angle}deg, ${colors[0]} 0%, ${colors[0]} 25%, transparent 25%, transparent 75%, ${colors[2]} 75%), + linear-gradient(${angle + 90}deg, ${colors[1]} 0%, ${colors[1]} 25%, transparent 25%, transparent 75%, ${colors[3]} 75%), + linear-gradient(${angle}deg, ${colors[2]} 0%, ${colors[3]} 100%) + `, + backgroundBlendMode: 'multiply, screen, normal', + }; + } + } + + case 'rings': { + const centerX = rng.int(30, 70); + const centerY = rng.int(30, 70); + return { + background: ` + repeating-radial-gradient(circle at ${centerX}% ${centerY}%, + ${colors[0]}66 0px, ${colors[0]}66 2px, + transparent 2px, transparent ${rng.int(15, 25)}px, + ${colors[1]}66 ${rng.int(15, 25)}px, ${colors[1]}66 ${rng.int(17, 27)}px, + transparent ${rng.int(17, 27)}px, transparent ${rng.int(35, 50)}px + ), + radial-gradient(circle at ${centerX}% ${centerY}%, ${colors[2]}88 0%, transparent 60%), + linear-gradient(${rng.int(0, 180)}deg, ${colors[3]}44, ${colors[0]}44) + `, + backgroundColor: bg, + }; + } + + case 'crystal': { + const facets = rng.int(4, 8); + const gradients = Array.from({ length: facets }, (_, i) => { + const startAngle = (360 / facets) * i; + const color = colors[i % colors.length]; + return `conic-gradient(from ${startAngle}deg at ${50 + rng.int(-20, 20)}% ${50 + rng.int(-20, 20)}%, ${color}88 0deg, transparent ${360/facets}deg)`; + }); + return { + background: [ + ...gradients, + `radial-gradient(circle at 50% 50%, ${colors[0]}44 0%, transparent 70%)`, + ].join(', '), + backgroundColor: bg, + }; + } + + default: + return { + background: `linear-gradient(135deg, ${colors[0]}, ${colors[1]})`, + }; + } +}; + +export const AlbumCover: React.FC = ({ seed, size = 'md', className = '', children }) => { + const coverStyle = useMemo(() => { + const rng = new SeededRandom(seed); + const palette = rng.pick(palettes); + return generatePattern(rng, palette); + }, [seed]); + + const sizeClasses: Record = { + xs: 'w-8 h-8', + sm: 'w-10 h-10', + md: 'w-12 h-12', + lg: 'w-14 h-14', + xl: 'w-48 h-48', + full: 'w-full h-full', + }; + + return ( +
+ {children} +
+ ); +}; + +export default AlbumCover; diff --git a/components/CreatePanel.tsx b/components/CreatePanel.tsx new file mode 100644 index 0000000..721be1f --- /dev/null +++ b/components/CreatePanel.tsx @@ -0,0 +1,1879 @@ +import React, { useState, useEffect, useRef, useCallback } from 'react'; +import { Sparkles, ChevronDown, Settings2, Trash2, Music2, Sliders, Dices, Hash, RefreshCw, Plus, Upload, Play, Pause } from 'lucide-react'; +import { GenerationParams, Song } from '../types'; +import { useAuth } from '../context/AuthContext'; +import { generateApi } from '../services/api'; + +interface ReferenceTrack { + id: string; + filename: string; + storage_key: string; + duration: number | null; + file_size_bytes: number | null; + tags: string[] | null; + created_at: string; + audio_url: string; +} + +interface CreatePanelProps { + onGenerate: (params: GenerationParams) => void; + isGenerating: boolean; + initialData?: { song: Song, timestamp: number } | null; +} + +const KEY_SIGNATURES = [ + '', + 'C major', 'C minor', + 'C# major', 'C# minor', + 'Db major', 'Db minor', + 'D major', 'D minor', + 'D# major', 'D# minor', + 'Eb major', 'Eb minor', + 'E major', 'E minor', + 'F major', 'F minor', + 'F# major', 'F# minor', + 'Gb major', 'Gb minor', + 'G major', 'G minor', + 'G# major', 'G# minor', + 'Ab major', 'Ab minor', + 'A major', 'A minor', + 'A# major', 'A# minor', + 'Bb major', 'Bb minor', + 'B major', 'B minor' +]; + +const TIME_SIGNATURES = ['', '2/4', '3/4', '4/4', '6/8']; + +const VOCAL_LANGUAGES = [ + { value: 'unknown', label: 'Auto / Instrumental' }, + { value: 'en', label: 'English' }, + { value: 'ja', label: 'Japanese' }, + { value: 'zh', label: 'Chinese' }, + { value: 'es', label: 'Spanish' }, + { value: 'de', label: 'German' }, + { value: 'fr', label: 'French' }, + { value: 'pt', label: 'Portuguese' }, + { value: 'ru', label: 'Russian' }, + { value: 'it', label: 'Italian' }, + { value: 'nl', label: 'Dutch' }, + { value: 'pl', label: 'Polish' }, + { value: 'tr', label: 'Turkish' }, + { value: 'vi', label: 'Vietnamese' }, + { value: 'cs', label: 'Czech' }, + { value: 'fa', label: 'Persian' }, + { value: 'id', label: 'Indonesian' }, + { value: 'ko', label: 'Korean' }, + { value: 'uk', label: 'Ukrainian' }, + { value: 'hu', label: 'Hungarian' }, + { value: 'ar', label: 'Arabic' }, + { value: 'sv', label: 'Swedish' }, + { value: 'ro', label: 'Romanian' }, + { value: 'el', label: 'Greek' }, +]; + +export const CreatePanel: React.FC = ({ onGenerate, isGenerating, initialData }) => { + const { isAuthenticated, token } = useAuth(); + + // Mode + const [customMode, setCustomMode] = useState(true); + + // Simple Mode + const [songDescription, setSongDescription] = useState(''); + + // Custom Mode + const [lyrics, setLyrics] = useState(''); + const [style, setStyle] = useState(''); + const [title, setTitle] = useState(''); + + // Common + const [instrumental, setInstrumental] = useState(false); + const [vocalLanguage, setVocalLanguage] = useState('en'); + + // Music Parameters + const [bpm, setBpm] = useState(0); + const [keyScale, setKeyScale] = useState(''); + const [timeSignature, setTimeSignature] = useState(''); + + // Advanced Settings + const [showAdvanced, setShowAdvanced] = useState(false); + const [duration, setDuration] = useState(-1); + const [batchSize, setBatchSize] = useState(2); + const [bulkCount, setBulkCount] = useState(1); // Number of independent generation jobs to queue + const [guidanceScale, setGuidanceScale] = useState(7.0); + const [randomSeed, setRandomSeed] = useState(true); + const [seed, setSeed] = useState(-1); + const [thinking, setThinking] = useState(true); + const [audioFormat, setAudioFormat] = useState<'mp3' | 'flac'>('mp3'); + const [inferenceSteps, setInferenceSteps] = useState(8); + const [inferMethod, setInferMethod] = useState<'ode' | 'sde'>('ode'); + const [shift, setShift] = useState(3.0); + + // LM Parameters (under Expert) + const [showLmParams, setShowLmParams] = useState(false); + const [lmTemperature, setLmTemperature] = useState(0.85); + const [lmCfgScale, setLmCfgScale] = useState(2.0); + const [lmTopK, setLmTopK] = useState(0); + const [lmTopP, setLmTopP] = useState(0.9); + const [lmNegativePrompt, setLmNegativePrompt] = useState('NO USER INPUT'); + + // Expert Parameters (now in Advanced section) + const [referenceAudioUrl, setReferenceAudioUrl] = useState(''); + const [sourceAudioUrl, setSourceAudioUrl] = useState(''); + const [audioCodes, setAudioCodes] = useState(''); + const [repaintingStart, setRepaintingStart] = useState(0); + const [repaintingEnd, setRepaintingEnd] = useState(-1); + const [instruction, setInstruction] = useState('Fill the audio semantic mask based on the given conditions:'); + const [audioCoverStrength, setAudioCoverStrength] = useState(1.0); + const [taskType, setTaskType] = useState('text2music'); + const [useAdg, setUseAdg] = useState(false); + const [cfgIntervalStart, setCfgIntervalStart] = useState(0.0); + const [cfgIntervalEnd, setCfgIntervalEnd] = useState(1.0); + const [customTimesteps, setCustomTimesteps] = useState(''); + const [useCotMetas, setUseCotMetas] = useState(true); + const [useCotCaption, setUseCotCaption] = useState(true); + const [useCotLanguage, setUseCotLanguage] = useState(true); + const [autogen, setAutogen] = useState(false); + const [constrainedDecodingDebug, setConstrainedDecodingDebug] = useState(false); + const [allowLmBatch, setAllowLmBatch] = useState(true); + const [getScores, setGetScores] = useState(false); + const [getLrc, setGetLrc] = useState(false); + const [scoreScale, setScoreScale] = useState(0.5); + const [lmBatchChunkSize, setLmBatchChunkSize] = useState(8); + const [trackName, setTrackName] = useState(''); + const [completeTrackClasses, setCompleteTrackClasses] = useState(''); + const [isFormatCaption, setIsFormatCaption] = useState(false); + + const [isUploadingReference, setIsUploadingReference] = useState(false); + const [isUploadingSource, setIsUploadingSource] = useState(false); + const [uploadError, setUploadError] = useState(null); + const [isFormatting, setIsFormatting] = useState(false); + const referenceInputRef = useRef(null); + const sourceInputRef = useRef(null); + const [showAudioModal, setShowAudioModal] = useState(false); + const [audioModalTarget, setAudioModalTarget] = useState<'reference' | 'source'>('reference'); + const [tempAudioUrl, setTempAudioUrl] = useState(''); + const [audioTab, setAudioTab] = useState<'reference' | 'source'>('reference'); + const referenceAudioRef = useRef(null); + const sourceAudioRef = useRef(null); + const [referencePlaying, setReferencePlaying] = useState(false); + const [sourcePlaying, setSourcePlaying] = useState(false); + const [referenceTime, setReferenceTime] = useState(0); + const [sourceTime, setSourceTime] = useState(0); + const [referenceDuration, setReferenceDuration] = useState(0); + const [sourceDuration, setSourceDuration] = useState(0); + + // Reference tracks modal state + const [referenceTracks, setReferenceTracks] = useState([]); + const [isLoadingTracks, setIsLoadingTracks] = useState(false); + const [playingTrackId, setPlayingTrackId] = useState(null); + const modalAudioRef = useRef(null); + const [modalTrackTime, setModalTrackTime] = useState(0); + const [modalTrackDuration, setModalTrackDuration] = useState(0); + + const getAudioLabel = (url: string) => { + try { + const parsed = new URL(url); + return decodeURIComponent(parsed.pathname.split('/').pop() || parsed.hostname); + } catch { + const parts = url.split('/'); + return decodeURIComponent(parts[parts.length - 1] || url); + } + }; + + // Resize Logic + const [lyricsHeight, setLyricsHeight] = useState(() => { + const saved = localStorage.getItem('acestep_lyrics_height'); + return saved ? parseInt(saved, 10) : 144; // Default h-36 is 144px (9rem * 16) + }); + const [isResizing, setIsResizing] = useState(false); + const lyricsRef = useRef(null); + + // Reuse Effect - must be after all state declarations + useEffect(() => { + if (initialData) { + setCustomMode(true); + setLyrics(initialData.song.lyrics); + setStyle(initialData.song.style); + setTitle(initialData.song.title); + setInstrumental(initialData.song.lyrics.length === 0); + } + }, [initialData]); + + useEffect(() => { + const handleMouseMove = (e: MouseEvent) => { + if (!isResizing) return; + + // Calculate new height based on mouse position relative to the lyrics container top + // We can't easily get the container top here without a ref to it, + // but we can use dy (delta y) from the previous position if we tracked it, + // OR simpler: just update based on movement if we track the start. + // + // Better approach for absolute sizing: + // 1. Get the bounding rect of the textarea wrapper on mount/resize start? + // We can just rely on the fact that we are dragging the bottom. + // So new height = currentMouseY - topOfElement. + + if (lyricsRef.current) { + const rect = lyricsRef.current.getBoundingClientRect(); + const newHeight = e.clientY - rect.top; + // detailed limits: min 96px (h-24), max 600px + if (newHeight > 96 && newHeight < 600) { + setLyricsHeight(newHeight); + } + } + }; + + const handleMouseUp = () => { + setIsResizing(false); + document.body.style.cursor = 'default'; + document.body.style.userSelect = 'auto'; + // Save height to localStorage + localStorage.setItem('acestep_lyrics_height', String(lyricsHeight)); + }; + + if (isResizing) { + window.addEventListener('mousemove', handleMouseMove); + window.addEventListener('mouseup', handleMouseUp); + document.body.style.cursor = 'ns-resize'; + document.body.style.userSelect = 'none'; // Prevent text selection while dragging + } + + return () => { + window.removeEventListener('mousemove', handleMouseMove); + window.removeEventListener('mouseup', handleMouseUp); + document.body.style.cursor = 'default'; + document.body.style.userSelect = 'auto'; + }; + }, [isResizing]); + + const startResizing = (e: React.MouseEvent) => { + e.preventDefault(); + setIsResizing(true); + }; + + const uploadAudio = async (file: File, target: 'reference' | 'source') => { + if (!token) { + setUploadError('Please sign in to upload audio.'); + return; + } + setUploadError(null); + const setUploading = target === 'reference' ? setIsUploadingReference : setIsUploadingSource; + const setUrl = target === 'reference' ? setReferenceAudioUrl : setSourceAudioUrl; + setUploading(true); + try { + const result = await generateApi.uploadAudio(file, token); + setUrl(result.url); + setShowAudioModal(false); + setTempAudioUrl(''); + } catch (err) { + const message = err instanceof Error ? err.message : 'Upload failed'; + setUploadError(message); + } finally { + setUploading(false); + } + }; + + const handleFileSelect = (e: React.ChangeEvent, target: 'reference' | 'source') => { + const file = e.target.files?.[0]; + if (file) { + void uploadAudio(file, target); + } + e.target.value = ''; + }; + + // Format handler - uses LLM to enhance style and auto-fill parameters + const handleFormat = async () => { + if (!token || !style.trim()) return; + setIsFormatting(true); + try { + const result = await generateApi.formatInput({ + caption: style, + lyrics: lyrics, + bpm: bpm > 0 ? bpm : undefined, + duration: duration > 0 ? duration : undefined, + keyScale: keyScale || undefined, + timeSignature: timeSignature || undefined, + temperature: lmTemperature, + topK: lmTopK > 0 ? lmTopK : undefined, + topP: lmTopP, + }, token); + + if (result.success) { + // Update fields with LLM-generated values + if (result.caption) setStyle(result.caption); + if (result.lyrics) setLyrics(result.lyrics); + if (result.bpm && result.bpm > 0) setBpm(result.bpm); + if (result.duration && result.duration > 0) setDuration(result.duration); + if (result.key_scale) setKeyScale(result.key_scale); + if (result.time_signature) setTimeSignature(result.time_signature); + if (result.language) setVocalLanguage(result.language); + setIsFormatCaption(true); + } else { + console.error('Format failed:', result.error || result.status_message); + alert(result.error || result.status_message || 'Format failed. Make sure the LLM is initialized.'); + } + } catch (err) { + console.error('Format error:', err); + alert('Format failed. The LLM may not be available.'); + } finally { + setIsFormatting(false); + } + }; + + const openAudioModal = (target: 'reference' | 'source') => { + setAudioModalTarget(target); + setTempAudioUrl(''); + setShowAudioModal(true); + void fetchReferenceTracks(); + }; + + const fetchReferenceTracks = useCallback(async () => { + if (!token) return; + setIsLoadingTracks(true); + try { + const response = await fetch('/api/reference-tracks', { + headers: { Authorization: `Bearer ${token}` } + }); + if (response.ok) { + const data = await response.json(); + setReferenceTracks(data.tracks || []); + } + } catch (err) { + console.error('Failed to fetch reference tracks:', err); + } finally { + setIsLoadingTracks(false); + } + }, [token]); + + const uploadReferenceTrack = async (file: File) => { + if (!token) { + setUploadError('Please sign in to upload audio.'); + return; + } + setUploadError(null); + setIsUploadingReference(true); + try { + const formData = new FormData(); + formData.append('audio', file); + + const response = await fetch('/api/reference-tracks', { + method: 'POST', + headers: { Authorization: `Bearer ${token}` }, + body: formData + }); + + if (!response.ok) { + const err = await response.json(); + throw new Error(err.error || 'Upload failed'); + } + + const data = await response.json(); + setReferenceTracks(prev => [data.track, ...prev]); + + // Also set as current reference/source + if (audioModalTarget === 'reference') { + setReferenceAudioUrl(data.track.audio_url); + } else { + setSourceAudioUrl(data.track.audio_url); + } + setShowAudioModal(false); + } catch (err) { + const message = err instanceof Error ? err.message : 'Upload failed'; + setUploadError(message); + } finally { + setIsUploadingReference(false); + } + }; + + const deleteReferenceTrack = async (trackId: string) => { + if (!token) return; + try { + const response = await fetch(`/api/reference-tracks/${trackId}`, { + method: 'DELETE', + headers: { Authorization: `Bearer ${token}` } + }); + if (response.ok) { + setReferenceTracks(prev => prev.filter(t => t.id !== trackId)); + if (playingTrackId === trackId) { + setPlayingTrackId(null); + if (modalAudioRef.current) { + modalAudioRef.current.pause(); + } + } + } + } catch (err) { + console.error('Failed to delete track:', err); + } + }; + + const useReferenceTrack = (track: ReferenceTrack) => { + if (audioModalTarget === 'reference') { + setReferenceAudioUrl(track.audio_url); + } else { + setSourceAudioUrl(track.audio_url); + } + setShowAudioModal(false); + setPlayingTrackId(null); + }; + + const toggleModalTrack = (track: ReferenceTrack) => { + if (playingTrackId === track.id) { + if (modalAudioRef.current) { + modalAudioRef.current.pause(); + } + setPlayingTrackId(null); + } else { + setPlayingTrackId(track.id); + if (modalAudioRef.current) { + modalAudioRef.current.src = track.audio_url; + modalAudioRef.current.play().catch(() => undefined); + } + } + }; + + const applyAudioUrl = () => { + if (!tempAudioUrl.trim()) return; + if (audioModalTarget === 'reference') { + setReferenceAudioUrl(tempAudioUrl.trim()); + setReferenceTime(0); + setReferenceDuration(0); + } else { + setSourceAudioUrl(tempAudioUrl.trim()); + setSourceTime(0); + setSourceDuration(0); + } + setShowAudioModal(false); + setTempAudioUrl(''); + }; + + const formatTime = (time: number) => { + if (!Number.isFinite(time) || time <= 0) return '0:00'; + const minutes = Math.floor(time / 60); + const seconds = Math.floor(time % 60); + return `${minutes}:${String(seconds).padStart(2, '0')}`; + }; + + const toggleAudio = (target: 'reference' | 'source') => { + const audio = target === 'reference' ? referenceAudioRef.current : sourceAudioRef.current; + if (!audio) return; + if (audio.paused) { + audio.play().catch(() => undefined); + } else { + audio.pause(); + } + }; + + const handleDrop = (e: React.DragEvent, target: 'reference' | 'source') => { + e.preventDefault(); + const file = e.dataTransfer.files?.[0]; + if (file) { + void uploadAudio(file, target); + } + }; + + const handleDragOver = (e: React.DragEvent) => { + e.preventDefault(); + }; + + const handleGenerate = () => { + // Bulk generation: loop bulkCount times + for (let i = 0; i < bulkCount; i++) { + // Seed handling: first job uses user's seed, rest get random seeds + let jobSeed = -1; + if (!randomSeed && i === 0) { + jobSeed = seed; + } else if (!randomSeed && i > 0) { + // Subsequent jobs get random seeds for variety + jobSeed = Math.floor(Math.random() * 4294967295); + } + + onGenerate({ + customMode, + songDescription: customMode ? undefined : songDescription, + prompt: lyrics, + lyrics, + style, + title: bulkCount > 1 ? `${title} (${i + 1})` : title, + instrumental, + vocalLanguage, + bpm, + keyScale, + timeSignature, + duration, + inferenceSteps, + guidanceScale, + batchSize, + randomSeed: randomSeed || i > 0, // Force random for subsequent bulk jobs + seed: jobSeed, + thinking, + audioFormat, + inferMethod, + shift, + lmTemperature, + lmCfgScale, + lmTopK, + lmTopP, + lmNegativePrompt, + referenceAudioUrl: referenceAudioUrl.trim() || undefined, + sourceAudioUrl: sourceAudioUrl.trim() || undefined, + audioCodes: audioCodes.trim() || undefined, + repaintingStart, + repaintingEnd, + instruction, + audioCoverStrength, + taskType, + useAdg, + cfgIntervalStart, + cfgIntervalEnd, + customTimesteps: customTimesteps.trim() || undefined, + useCotMetas, + useCotCaption, + useCotLanguage, + autogen, + constrainedDecodingDebug, + allowLmBatch, + getScores, + getLrc, + scoreScale, + lmBatchChunkSize, + trackName: trackName.trim() || undefined, + completeTrackClasses: (() => { + const parsed = completeTrackClasses + .split(',') + .map((item) => item.trim()) + .filter(Boolean); + return parsed.length ? parsed : undefined; + })(), + isFormatCaption, + }); + } + + // Reset bulk count after generation + if (bulkCount > 1) { + setBulkCount(1); + } + }; + + return ( +
+
+ handleFileSelect(e, 'reference')} + className="hidden" + /> + handleFileSelect(e, 'source')} + className="hidden" + /> +