You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, ringStyle = 'US', durationSeconds = 3) {
const sampleRate = 44100;
const numSamples = sampleRate * durationSeconds;
const samples = new Int16Array(numSamples);
// Synthesize classic telephone ringtone sound
for (let i = 0; i < numSamples; i++) {
const t = i / sampleRate;
let signal = 0;
let modFreq = 20; // Amplitude modulation frequency to simulate mechanical bell
if (ringStyle === 'UK') {
// UK standard (400 Hz + 450 Hz)
signal = 0.5 * Math.sin(2 * Math.PI * 400 * t) + 0.5 * Math.sin(2 * Math.PI * 450 * t);
modFreq = 25;
} else if (ringStyle === 'Europe') {
// European standard (425 Hz)
signal = Math.sin(2 * Math.PI * 425 * t);
modFreq = 25;
} else {
// US standard (440 Hz + 480 Hz)
signal = 0.5 * Math.sin(2 * Math.PI * 440 * t) + 0.5 * Math.sin(2 * Math.PI * 480 * t);
modFreq = 20;
}
// Apply AM for vintage bell feel
const am = (Math.sin(2 * Math.PI * modFreq * t) + 1.0) / 2.0;
// Envelope (fade in/out for click reduction)
let env = 1.0;
const fadeTime = 0.05;
if (t < fadeTime) env = t / fadeTime;
if (t > durationSeconds - fadeTime) env = (durationSeconds - t) / fadeTime;
// Multiply signal, scale to 16-bit PCM integer range
let val = signal * am * env * 0.8;
samples[i] = val * 32767;
}
let audioBlob;
let ext = 'mp3';
try {
// Dynamically load lamejs if it's not present to generate genuine MP3
if (!window.lamejs) {
await new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/lamejs/1.2.1/lame.min.js';
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
const mp3encoder = new window.lamejs.Mp3Encoder(1, sampleRate, 128); // Mono, 44.1kHz, 128kbps
const mp3Data = [];
const sampleBlockSize = 1152;
for (let i = 0; i < samples.length; i += sampleBlockSize) {
const chunk = samples.subarray(i, i + sampleBlockSize);
const mp3buf = mp3encoder.encodeBuffer(chunk);
if (mp3buf.length > 0) {
mp3Data.push(new Int8Array(mp3buf));
}
}
const lastBuf = mp3encoder.flush();
if (lastBuf.length > 0) {
mp3Data.push(new Int8Array(lastBuf));
}
audioBlob = new Blob(mp3Data, { type: 'audio/mp3' });
} catch (err) {
console.warn("Failed to load LameJS for MP3, falling back to WAV.", err);
ext = 'wav';
// Manual WAV encoding fallback
const buffer = new ArrayBuffer(44 + samples.length * 2);
const view = new DataView(buffer);
const writeString = (v, offset, str) => {
for (let i = 0; i < str.length; i++) v.setUint8(offset + i, str.charCodeAt(i));
};
writeString(view, 0, 'RIFF');
view.setUint32(4, 36 + samples.length * 2, true);
writeString(view, 8, 'WAVE');
writeString(view, 12, 'fmt ');
view.setUint32(16, 16, true);
view.setUint16(20, 1, true);
view.setUint16(22, 1, true);
view.setUint32(24, sampleRate, true);
view.setUint32(28, sampleRate * 2, true);
view.setUint16(32, 2, true);
view.setUint16(34, 16, true);
writeString(view, 36, 'data');
view.setUint32(40, samples.length * 2, true);
for (let i = 0; i < samples.length; i++) {
view.setInt16(44 + i * 2, samples[i], true);
}
audioBlob = new Blob([view], { type: 'audio/wav' });
}
const audioUrl = URL.createObjectURL(audioBlob);
// Build the UI Container
const container = document.createElement('div');
container.style.cssText = `
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
text-align: center;
border: 1px solid #e0e0e0;
border-radius: 12px;
padding: 30px 20px;
max-width: 350px;
margin: 0 auto;
box-shadow: 0 8px 24px rgba(0,0,0,0.08);
background: linear-gradient(135deg, #ffffff 0%, #f7f9fc 100%);
`;
// Incorporate the originalImg as "cover art"
const artWrapper = document.createElement('div');
artWrapper.style.cssText = `
width: 140px;
height: 140px;
margin: 0 auto 20px auto;
border-radius: 50%;
overflow: hidden;
box-shadow: 0 6px 16px rgba(0,0,0,0.15);
border: 4px solid #fff;
`;
const clonedImg = new Image();
clonedImg.src = originalImg.src;
clonedImg.style.cssText = `
width: 100%;
height: 100%;
object-fit: cover;
`;
artWrapper.appendChild(clonedImg);
container.appendChild(artWrapper);
const title = document.createElement('h2');
title.style.cssText = 'margin: 0 0 5px 0; color: #333; font-size: 22px;';
title.innerText = 'Ringtone Mp3';
container.appendChild(title);
const subtitle = document.createElement('p');
subtitle.style.cssText = 'margin: 0 0 20px 0; color: #777; font-size: 14px;';
subtitle.innerText = `Telephone Ringtone (${ringStyle} Style)`;
container.appendChild(subtitle);
const audioPlayer = document.createElement('audio');
audioPlayer.controls = true;
audioPlayer.src = audioUrl;
audioPlayer.style.cssText = 'width: 100%; margin-bottom: 25px; outline: none;';
container.appendChild(audioPlayer);
const downloadLink = document.createElement('a');
downloadLink.href = audioUrl;
downloadLink.download = `telephone_ring_music.${ext}`;
downloadLink.style.cssText = `
display: inline-block;
background-color: #007bff;
color: white;
text-decoration: none;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
font-size: 15px;
transition: background 0.2s ease, transform 0.1s ease;
box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3);
`;
// Hover effects via JS inline logic
downloadLink.onmouseover = () => downloadLink.style.backgroundColor = '#0056b3';
downloadLink.onmouseout = () => downloadLink.style.backgroundColor = '#007bff';
downloadLink.onmousedown = () => downloadLink.style.transform = 'scale(0.97)';
downloadLink.onmouseup = () => downloadLink.style.transform = 'scale(1)';
downloadLink.innerText = `Download ${ext.toUpperCase()}`;
container.appendChild(downloadLink);
return container;
}
Apply Changes