开云体育

ctrl + shift + ? for shortcuts
© 2025 开云体育

Re: headerless vced new voice

 

开云体育

In case you’re wondering what AI is capable to do for you (and how optimistic it is about the results.. didn’t work out / this is first try)

Claude.ai:

I'll help you rebuild the interactive diagram of a Yamaha DX7 envelope based on the provided code and documentation. Let me analyze the information and create a plan.

From the documents, I can see:

  1. A detailed description of the DX7 envelope logic in the PDF
  2. C++ implementation code in the env.cc.rtf file

The DX7 envelope has a distinctive 4-stage design with rates and levels that create its characteristic sound. The envelope starts at L4, rises to L1, then falls to L2, and continues through L3 to L4 during release.

Here's my approach to rebuild the interactive diagram:

  1. First, I'll create an HTML structure with SVG for the envelope visualization
  2. Implement the core envelope calculation logic from the C++ code
  3. Add interactive controls for the envelope parameters
  4. Connect the controls to update the visualization in real-time

Let me create this as a single HTML file with embedded JavaScript:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Yamaha DX7 Envelope</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
            max-width: 1000px;
            margin: 0 auto;
            padding: 20px;
            color: #333;
            line-height: 1.6;
        }
        h1 {
            color: #0066cc;
            border-bottom: 1px solid #ddd;
            padding-bottom: 10px;
        }
        .envelope-container {
            border: 1px solid #ccc;
            border-radius: 5px;
            padding: 20px;
            margin: 20px 0;
            background-color: #f9f9f9;
        }
        .controls {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
            gap: 15px;
            margin-bottom: 20px;
        }
        .control-group {
            margin-bottom: 10px;
        }
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        input[type="range"] {
            width: 100%;
        }
        .value-display {
            display: inline-block;
            width: 40px;
            text-align: right;
            margin-left: 5px;
        }
        .svg-container {
            background-color: white;
            border: 1px solid #ddd;
            border-radius: 3px;
            overflow: hidden;
        }
        svg {
            display: block;
            width: 100%;
            height: 300px;
        }
        .description {
            background-color: #f0f0f0;
            border-left: 4px solid #0066cc;
            padding: 10px 15px;
            margin: 20px 0;
            font-size: 0.9em;
        }
        .axis-label {
            font-size: 12px;
            fill: #666;
        }
        .animation-controls {
            margin-top: 10px;
            text-align: center;
        }
        button {
            background-color: #0066cc;
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 4px;
            cursor: pointer;
            margin: 0 5px;
        }
        button:hover {
            background-color: #0055aa;
        }
        .key-state {
            display: inline-block;
            margin-left: 10px;
            padding: 5px 10px;
            border-radius: 3px;
            background-color: #eee;
        }
    </style>
</head>
<body>
    <h1>Yamaha DX7 Envelope Interactive Diagram</h1>
    
    <div class="description">
        <p>This is an interactive visualization of the Yamaha DX7 synthesizer's envelope generator. The DX7 uses a 4-stage ADSR-like envelope with rates (R1-R4) and levels (L1-L4). Adjust the sliders to see how the envelope shape changes.</p>
    </div>
    
    <div class="envelope-container">
        <div class="controls">
            <div class="control-group">
                <label for="r1">Rate 1 (Attack): <span class="value-display" id="r1-value">99</span></label>
                <input type="range" id="r1" min="0" max="99" value="99">
            </div>
            <div class="control-group">
                <label for="r2">Rate 2 (First Decay): <span class="value-display" id="r2-value">99</span></label>
                <input type="range" id="r2" min="0" max="99" value="99">
            </div>
            <div class="control-group">
                <label for="r3">Rate 3 (Second Decay): <span class="value-display" id="r3-value">99</span></label>
                <input type="range" id="r3" min="0" max="99" value="99">
            </div>
            <div class="control-group">
                <label for="r4">Rate 4 (Release): <span class="value-display" id="r4-value">70</span></label>
                <input type="range" id="r4" min="0" max="99" value="70">
            </div>
            <div class="control-group">
                <label for="l1">Level 1 (Peak): <span class="value-display" id="l1-value">99</span></label>
                <input type="range" id="l1" min="0" max="99" value="99">
            </div>
            <div class="control-group">
                <label for="l2">Level 2 (Sustain 1): <span class="value-display" id="l2-value">90</span></label>
                <input type="range" id="l2" min="0" max="99" value="90">
            </div>
            <div class="control-group">
                <label for="l3">Level 3 (Sustain 2): <span class="value-display" id="l3-value">80</span></label>
                <input type="range" id="l3" min="0" max="99" value="80">
            </div>
            <div class="control-group">
                <label for="l4">Level 4 (End): <span class="value-display" id="l4-value">0</span></label>
                <input type="range" id="l4" min="0" max="99" value="0">
            </div>
            <div class="control-group">
                <label for="ol">Output Level: <span class="value-display" id="ol-value">99</span></label>
                <input type="range" id="ol" min="0" max="99" value="99">
            </div>
            <div class="control-group">
                <label for="rs">Rate Scaling: <span class="value-display" id="rs-value">0</span></label>
                <input type="range" id="rs" min="0" max="7" value="0">
            </div>
        </div>
        
        <div class="svg-container">
            <svg id="envelope-svg" viewBox="0 0 1000 300"></svg>
        </div>
        
        <div class="animation-controls">
            <button id="trigger-button">Trigger Note</button>
            <button id="release-button" disabled>Release Note</button>
            <span class="key-state" id="key-state">Key Up</span>
        </div>
    </div>
    
    <script>
        // Envelope parameters
        const params = {
            rates: [99, 99, 99, 70],
            levels: [99, 90, 80, 0],
            outputLevel: 99,
            rateScaling: 0
        };
        
        // Level lookup table for output level 0-19 (from the C++ code)
        const levellut = [
            0, 5, 9, 13, 17, 20, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 42, 43, 45, 46
        ];
        
        // SVG setup
        const svg = document.getElementById('envelope-svg');
        const svgWidth = 1000;
        const svgHeight = 300;
        const padding = { top: 30, right: 30, bottom: 50, left: 50 };
        const graphWidth = svgWidth - padding.left - padding.right;
        const graphHeight = svgHeight - padding.top - padding.bottom;
        
        // Create graph elements
        const axisGroup = document.createElementNS("http://www.w3.org/2000/svg", "g");
        axisGroup.setAttribute("transform", `translate(${padding.left}, ${padding.top})`);
        svg.appendChild(axisGroup);
        
        const envelopePath = document.createElementNS("http://www.w3.org/2000/svg", "path");
        envelopePath.setAttribute("fill", "none");
        envelopePath.setAttribute("stroke", "#0066cc");
        envelopePath.setAttribute("stroke-width", "3");
        axisGroup.appendChild(envelopePath);
        
        const currentPositionMarker = document.createElementNS("http://www.w3.org/2000/svg", "circle");
        currentPositionMarker.setAttribute("r", "6");
        currentPositionMarker.setAttribute("fill", "red");
        currentPositionMarker.style.display = "none";
        axisGroup.appendChild(currentPositionMarker);
        
        // Draw axes
        const xAxis = document.createElementNS("http://www.w3.org/2000/svg", "line");
        xAxis.setAttribute("x1", "0");
        xAxis.setAttribute("y1", `${graphHeight}`);
        xAxis.setAttribute("x2", `${graphWidth}`);
        xAxis.setAttribute("y2", `${graphHeight}`);
        xAxis.setAttribute("stroke", "#999");
        xAxis.setAttribute("stroke-width", "1");
        axisGroup.appendChild(xAxis);
        
        const yAxis = document.createElementNS("http://www.w3.org/2000/svg", "line");
        yAxis.setAttribute("x1", "0");
        yAxis.setAttribute("y1", "0");
        yAxis.setAttribute("x2", "0");
        yAxis.setAttribute("y2", `${graphHeight}`);
        yAxis.setAttribute("stroke", "#999");
        yAxis.setAttribute("stroke-width", "1");
        axisGroup.appendChild(yAxis);
        
        // Axis labels
        const xLabel = document.createElementNS("http://www.w3.org/2000/svg", "text");
        xLabel.setAttribute("class", "axis-label");
        xLabel.setAttribute("x", `${graphWidth / 2}`);
        xLabel.setAttribute("y", `${graphHeight + 30}`);
        xLabel.setAttribute("text-anchor", "middle");
        xLabel.textContent = "Time";
        axisGroup.appendChild(xLabel);
        
        const yLabel = document.createElementNS("http://www.w3.org/2000/svg", "text");
        yLabel.setAttribute("class", "axis-label");
        yLabel.setAttribute("x", "-15");
        yLabel.setAttribute("y", `${graphHeight / 2}`);
        yLabel.setAttribute("transform", `rotate(-90, -15, ${graphHeight / 2})`);
        yLabel.setAttribute("text-anchor", "middle");
        yLabel.textContent = "Level";
        axisGroup.appendChild(yLabel);
        
        // Add grid lines
        for (let i = 0; i <= 4; i++) {
            const y = graphHeight * (1 - i / 4);
            const gridLine = document.createElementNS("http://www.w3.org/2000/svg", "line");
            gridLine.setAttribute("x1", "0");
            gridLine.setAttribute("y1", `${y}`);
            gridLine.setAttribute("x2", `${graphWidth}`);
            gridLine.setAttribute("y2", `${y}`);
            gridLine.setAttribute("stroke", "#ddd");
            gridLine.setAttribute("stroke-width", "1");
            gridLine.setAttribute("stroke-dasharray", "3,3");
            axisGroup.appendChild(gridLine);
            
            const gridLabel = document.createElementNS("http://www.w3.org/2000/svg", "text");
            gridLabel.setAttribute("class", "axis-label");
            gridLabel.setAttribute("x", "-10");
            gridLabel.setAttribute("y", `${y + 5}`);
            gridLabel.setAttribute("text-anchor", "end");
            gridLabel.textContent = `${i * 25}`;
            axisGroup.appendChild(gridLabel);
        }
        
        // DX7 envelope calculation logic
        const ENV = {
            // Convert level parameter to actual level
            scaleOutlevel: function(outlevel) {
                return outlevel >= 20 ? 28 + outlevel : levellut[outlevel];
            },
            
            // Calculate display amplitude (0-1 scale) for a given level
            levelToAmplitude: function(level, outputLevel) {
                const scaledLevel = ENV.scaleOutlevel(level) >> 1;
                let actualLevel = (scaledLevel << 6) + outputLevel - 4256;
                actualLevel = actualLevel < 16 ? 16 : actualLevel;
                
                // Convert to 0-1 range for display
                return 1 - (actualLevel / 6000);
            },
            
            // Calculate the time for a rate value at 44.1kHz
            rateToTime: function(rate, rateScaling) {
                // Apply rate scaling
                let qrate = Math.floor((rate * 41) / 64);
                qrate += rateScaling;
                qrate = Math.min(qrate, 63);
                
                // Calculate rate based on quantized rate (DX7 algorithm)
                const base = Math.pow(2, qrate >> 2);
                const fraction = 1 + 0.25 * (qrate & 3);
                const rateMs = 1 / (0.2819 * base * fraction);
                
                // Convert to milliseconds
                return rateMs * 1000;
            }
        };
        
        // Simulation variables
        let keyDown = false;
        let currentIndex = 0;
        let currentTime = 0;
        let currentLevel = 0;
        let animationFrameId = null;
        let startTime = 0;
        let lastTime = 0;
        
        // Calculate envelope points for display (static view)
        function calculateEnvelopePoints() {
            const points = [];
            let x = 0;
            let timeScale = 0.25; // Scale time to fit visually
            
            // Start at L4
            const l4Amp = ENV.levelToAmplitude(params.levels[3], params.outputLevel);
            points.push([0, l4Amp]);
            
            // R1 (attack): L4 to L1
            const r1Time = ENV.rateToTime(params.rates[0], params.rateScaling) * timeScale;
            const l1Amp = ENV.levelToAmplitude(params.levels[0], params.outputLevel);
            x += r1Time;
            points.push([x, l1Amp]);
            
            // R2 (first decay): L1 to L2
            const r2Time = ENV.rateToTime(params.rates[1], params.rateScaling) * timeScale;
            const l2Amp = ENV.levelToAmplitude(params.levels[1], params.outputLevel);
            x += r2Time;
            points.push([x, l2Amp]);
            
            // R3 (second decay/sustain): L2 to L3
            const r3Time = ENV.rateToTime(params.rates[2], params.rateScaling) * timeScale;
            const l3Amp = ENV.levelToAmplitude(params.levels[2], params.outputLevel);
            x += r3Time;
            points.push([x, l3Amp]);
            
            // Sustain point (extend L3 for visual clarity)
            points.push([x + 100, l3Amp]);
            
            // R4 (release): L3 to L4
            const r4Time = ENV.rateToTime(params.rates[3], params.rateScaling) * timeScale;
            const releaseStartX = x + 100;
            x = releaseStartX + r4Time;
            points.push([x, l4Amp]);
            
            return { points, releasePoint: releaseStartX };
        }
        
        // Draw the envelope
        function drawEnvelope() {
            const { points, releasePoint } = calculateEnvelopePoints();
            
            // Normalize points to the graph dimensions
            const maxX = points[points.length - 1][0];
            const normalizedPoints = points.map(point => [
                (point[0] / maxX) * graphWidth,
                point[1] * graphHeight
            ]);
            
            // Create SVG path
            let pathData = `M ${normalizedPoints[0][0]},${graphHeight - normalizedPoints[0][1]} `;
            for (let i = 1; i < normalizedPoints.length; i++) {
                pathData += `L ${normalizedPoints[i][0]},${graphHeight - normalizedPoints[i][1]} `;
            }
            envelopePath.setAttribute("d", pathData);
            
            // Add a release marker
            const releaseMarker = document.getElementById('release-marker') || 
                document.createElementNS("http://www.w3.org/2000/svg", "line");
            releaseMarker.id = 'release-marker';
            releaseMarker.setAttribute("x1", (releasePoint / maxX) * graphWidth);
            releaseMarker.setAttribute("y1", "0");
            releaseMarker.setAttribute("x2", (releasePoint / maxX) * graphWidth);
            releaseMarker.setAttribute("y2", graphHeight);
            releaseMarker.setAttribute("stroke", "#ff6600");
            releaseMarker.setAttribute("stroke-width", "2");
            releaseMarker.setAttribute("stroke-dasharray", "5,5");
            axisGroup.appendChild(releaseMarker);
            
            // Add a release label
            const releaseLabel = document.getElementById('release-label') || 
                document.createElementNS("http://www.w3.org/2000/svg", "text");
            releaseLabel.id = 'release-label';
            releaseLabel.setAttribute("class", "axis-label");
            releaseLabel.setAttribute("x", (releasePoint / maxX) * graphWidth);
            releaseLabel.setAttribute("y", "-10");
            releaseLabel.setAttribute("text-anchor", "middle");
            releaseLabel.textContent = "Key Release";
            axisGroup.appendChild(releaseLabel);
        }
        
        // Animation
        function startAnimation() {
            if (animationFrameId) {
                cancelAnimationFrame(animationFrameId);
            }
            
            keyDown = true;
            currentIndex = 0;
            currentLevel = ENV.levelToAmplitude(params.levels[3], params.outputLevel);
            currentTime = 0;
            startTime = performance.now();
            lastTime = startTime;
            
            document.getElementById('key-state').textContent = "Key Down";
            document.getElementById('trigger-button').disabled = true;
            document.getElementById('release-button').disabled = false;
            
            currentPositionMarker.style.display = "block";
            
            animationFrameId = requestAnimationFrame(animate);
        }
        
        function releaseKey() {
            if (keyDown) {
                keyDown = false;
                currentIndex = 3; // Go to release phase
                
                document.getElementById('key-state').textContent = "Key Released";
                document.getElementById('release-button').disabled = true;
            }
        }
        
        function animate(timestamp) {
            const deltaTime = timestamp - lastTime;
            lastTime = timestamp;
            currentTime += deltaTime;
            
            updateAnimationPosition();
            
            if (currentIndex <= 4) {
                animationFrameId = requestAnimationFrame(animate);
            } else {
                resetAnimation();
            }
        }
        
        function updateAnimationPosition() {
            const { points, releasePoint } = calculateEnvelopePoints();
            const maxX = points[points.length - 1][0];
            
            let targetX, targetY;
            
            if (!keyDown && currentIndex === 3) {
                // We're in release phase after key up
                const releaseTime = ENV.rateToTime(params.rates[3], params.rateScaling) * 0.25;
                const progress = Math.min((currentTime - (startTime + releasePoint)) / releaseTime, 1);
                
                const startAmp = ENV.levelToAmplitude(params.levels[2], params.outputLevel);
                const endAmp = ENV.levelToAmplitude(params.levels[3], params.outputLevel);
                currentLevel = startAmp + progress * (endAmp - startAmp);
                
                targetX = releasePoint + (progress * (maxX - releasePoint));
                targetY = currentLevel;
                
                if (progress >= 0.99) {
                    currentIndex = 5; // End animation
                }
            } else {
                // Normal envelope progression
                const timeThresholds = [
                    0,
                    ENV.rateToTime(params.rates[0], params.rateScaling) * 0.25,
                    ENV.rateToTime(params.rates[1], params.rateScaling) * 0.25,
                    ENV.rateToTime(params.rates[2], params.rateScaling) * 0.25
                ];
                
                let elapsedTime = currentTime - startTime;
                
                // Check if we need to advance to the next stage
                if (currentIndex < 3 && elapsedTime >= timeThresholds.slice(0, currentIndex + 1).reduce((a, b) => a + b, 0)) {
                    currentIndex++;
                }
                
                // Calculate position based on current phase
                let phaseStartTime = 0;
                for (let i = 0; i < currentIndex; i++) {
                    phaseStartTime += timeThresholds[i];
                }
                
                const phaseTime = timeThresholds[currentIndex];
                const phaseProgress = Math.min((elapsedTime - phaseStartTime) / phaseTime, 1);
                
                const startLevel = currentIndex === 0 
                    ? ENV.levelToAmplitude(params.levels[3], params.outputLevel)
                    : ENV.levelToAmplitude(params.levels[currentIndex - 1], params.outputLevel);
                const endLevel = ENV.levelToAmplitude(params.levels[currentIndex], params.outputLevel);
                
                currentLevel = startLevel + phaseProgress * (endLevel - startLevel);
                
                // Calculate X position
                let xPos = 0;
                for (let i = 0; i < currentIndex; i++) {
                    xPos += timeThresholds[i];
                }
                xPos += phaseProgress * phaseTime;
                
                targetX = xPos;
                targetY = currentLevel;
                
                // If we're in the sustain phase (index 3), extend horizontally
                if (currentIndex === 3 && phaseProgress >= 1) {
                    targetX = points[3][0] + (elapsedTime - phaseStartTime - phaseTime) * 0.1;
                    if (targetX >= releasePoint) {
                        targetX = releasePoint;
                    }
                }
            }
            
            // Update position marker
            currentPositionMarker.setAttribute("cx", (targetX / maxX) * graphWidth);
            currentPositionMarker.setAttribute("cy", graphHeight - (targetY * graphHeight));
        }
        
        function resetAnimation() {
            if (animationFrameId) {
                cancelAnimationFrame(animationFrameId);
                animationFrameId = null;
            }
            
            keyDown = false;
            currentIndex = 0;
            currentPositionMarker.style.display = "none";
            
            document.getElementById('key-state').textContent = "Key Up";
            document.getElementById('trigger-button').disabled = false;
            document.getElementById('release-button').disabled = true;
        }
        
        // Event handlers
        document.getElementById('trigger-button').addEventListener('click', startAnimation);
        document.getElementById('release-button').addEventListener('click', releaseKey);
        
        // Connect all sliders
        const sliders = [
            { id: 'r1', valueId: 'r1-value', index: 0, type: 'rate' },
            { id: 'r2', valueId: 'r2-value', index: 1, type: 'rate' },
            { id: 'r3', valueId: 'r3-value', index: 2, type: 'rate' },
            { id: 'r4', valueId: 'r4-value', index: 3, type: 'rate' },
            { id: 'l1', valueId: 'l1-value', index: 0, type: 'level' },
            { id: 'l2', valueId: 'l2-value', index: 1, type: 'level' },
            { id: 'l3', valueId: 'l3-value', index: 2, type: 'level' },
            { id: 'l4', valueId: 'l4-value', index: 3, type: 'level' }
        ];
        
        sliders.forEach(slider => {
            const input = document.getElementById(slider.id);
            const valueDisplay = document.getElementById(slider.valueId);
            
            // Set initial value display
            valueDisplay.textContent = input.value;
            
            // Add event listener
            input.addEventListener('input', () => {
                valueDisplay.textContent = input.value;
                if (slider.type === 'rate') {
                    params.rates[slider.index] = parseInt(input.value, 10);
                } else {
                    params.levels[slider.index] = parseInt(input.value, 10);
                }
                drawEnvelope();
            });
        });
        
        // Output level and rate scaling sliders
        const olSlider = document.getElementById('ol');
        const olValue = document.getElementById('ol-value');
        olValue.textContent = olSlider.value;
        olSlider.addEventListener('input', () => {
            olValue.textContent = olSlider.value;
            params.outputLevel = parseInt(olSlider.value, 10);
            drawEnvelope();
        });
        
        const rsSlider = document.getElementById('rs');
        const rsValue = document.getElementById('rs-value');
        rsValue.textContent = rsSlider.value;
        rsSlider.addEventListener('input', () => {
            rsValue.textContent = rsSlider.value;
            params.rateScaling = parseInt(rsSlider.value, 10);
            drawEnvelope();
        });
        
        // Initial draw
        drawEnvelope();
    </script>
</body>
</html>

This interactive diagram of the Yamaha DX7 envelope implements the core logic from the provided documents. Here's what I've created:

  1. Visual representation: An SVG graph that shows the envelope shape with proper scaling for both amplitude and time.

  2. Parameter controls: Sliders for all the key DX7 envelope parameters:

    • Rates (R1-R4): Control how quickly the envelope moves between stages
    • Levels (L1-L4): Define the amplitude at each stage
    • Output Level: Overall amplitude scaling
    • Rate Scaling: Parameter that affects envelope timing
  3. Real-time animation: A simulation that shows how the envelope progresses in real-time, including:

    • A trigger button to start the envelope
    • A release button to enter the release phase
    • A position marker showing the current point on the envelope
  4. Accurate timing calculations: The code implements the DX7's distinctive envelope timing calculations based on the C++ implementation, including:

    • Level scaling using the lookup table for low values
    • Rate calculations with proper quantization
    • Attack/decay curve characteristics

To use the diagram:

  1. Adjust the sliders to modify the envelope shape
  2. Click "Trigger Note" to see the envelope in action
  3. Click "Release Note" to hear how the release phase sounds

This implementation is compatible with macOS 14.7.1 and Xcode 15.2, running in any modern browser. Would you like me to explain any specific part of the implementation in more detail?


Maybe someone has a better grip on AI. I didn’t get closer with the next prompts.


Here is what I could find about the envelope:

DX7 Envelope

The envelope logic is fairly simple, but also quite musically expressive. The main parameters are four levels and rates, and also the output level. The shape of the envelope is asymmetrical - while the decay portions are purely exponential, the attack portions are a more complex shape approximating linear. This asymmetry is visible in the envelope figures in Chowning's original paper on FM synthesis. Chowning says, "A general characteristic of percussive sounds is that the decay shape of the envelope is roughly exponential as shown in Fig. 14", while the attacks shown in examples of envelopes for brass and woodwind sounds is much closer to linear.?

The full state of the idealized envelope is represented as an _index_ of which part of the envelope is active (labeled 0-3 in this discussion), combined with a _level_. Typically, the envelope starts out at L4 and increases to L1. Then, when it reaches the _target_ of L1, the index increments, and it proceeds to L2 (either by decay or attack, depending on whether L1 or L2 is greater).?

The conversion from level parameter (L1, L2, L3, L4 in the patch) to actual level is as follows:?

The output level is scaled similarly, but is just 28 + l for values 20..99. It has twice the precision of the level parameters. The exact lookup table for values 0..19 is [0,].?

Then, the total level is 64 `*` actual level + 32 `*` output level, normalized for full scale. This "total level" is in units of approx .0235 dB (20 log10(2) / 256), so that 256 of these steps doubles the amplitude.?

From measurement of timing, the minimum level seems to be clipped at 3824 counts from full scale -> 14.9375 doublings. Note, however, that velocity values > 100 can cause amplitudes greater than full scale. Full scale means both L and output level set to 99 in the patch, and no additional scaling.?

As mentioned above, the decay shape is simpler than the attack. An exponential decay corresponds to a linear change in dB units. First, the R parameter in the patch (range 0..99) is converted to a 6 bit value (0..63), by the formula qrate = (rate `*` 41) / 64.?

The rate of decay is then 0.2819 `*` 2(qrate / 4) `*` (1 + 0.25 `*` (qrate mod 4)) dB/s. This is a reasaonably good approximation to 0.28 `*` 2(qrate `*` 0.25).?

Attack is based on decay, multiplying it by a factor dependent on the current level. In .0235 dB units, this factor is 2 + floor((full scale - current level) / 256). Also, level _immediately_ rises to 39.98 dB (1700 steps) above the minimum level, which helps create a crisper attack.?

The output level is computed once, at the beginning of the note, and affects both the overall amplitude of the operator and also the timing. In addition to the "output level" setting in the patch, output level is also affected by velocity and scaling.?

The output level in the patch is in the range 0..99, and this is scaled in units of 0.7526 dB (ie 32 steps).?

DX 7 Hardware

Measurement of the DX7 reveals quite rich detail on how envelopes are actually computed. Clearly the resolution for amplitude is .0235 dB, and there are 12 bits total (for a maximum dynamic range of 72.25 dB).?

At a qrate of 0, the amplitude decreases by one step every 4096 samples, in other words halves every 220 samples. Each increase of 4 doubles the clock rate. Careful examination reveals that fractional multiples of qrate (ie qrate is not a multiple of 4) are clocked out using a pattern:?

For attacks, instead of decrementing by 1, the factor is added (thus, no actual multiplication is needed). When the clock rate increases to the point where the increment would be needed more than once per sample clock (ie for qrate >= 48), the increment value is shifted left by (qrate / 4) - 11 instead, and the increment (masked by the bit pattern above) is applied every single sample clock.?


I had some javascript code to compute the changes is level (which I couldn’t transform to c(++) back then.. maybe I’ll find it next time I have some free time..

Benjamin

(This one is a though puzzle..)




Re: headerless vced new voice

 

开云体育

It’s a riddle/puzzle to solve.. -> makes it more interesting than just another patch.

What I thought of was: it would be very cool, if one could copy and reorganize branches of patches:
Copy carrier and attached modulations from one patch/algorithm to another: as there is a loudness( and complexety) difference between patches with more carriers to ones with more modulators.
(I think this is one thing dexed didn’t replicate, but was noticeable while experimenting with my dx9/dx7II - I miss the time, when I still had time to thing about those things..)

Also the usability would be(was) very important to me:
It’s a great difference, if you can access any parameter, somehow (edisyn for example) or to have the parameters displayed in a pleasent way, while being able to edit things in context.

(I tried to display the envelopes in a realistic way:

?the link of the interactive dx envelope is broken there (as information seemed disappearing back then, but still here:

)


A good sysex editor should make the structure of the synth more transparent (by using symmetry and thought full placement and refinements of the parameters:
I like an approach where it’s like a table: one side has the operators the other the parameters > no double informations op1 level 1, op2 level 1)

Greetings from Hamburg,
Benjamin

Ps. I’m trying to get a working Atari again (so I’m a bit curious about programming it too)

my new dx atari program "voice creator" coming along fine... any features or function suggestions please reccomend


Re: headerless vced new voice

 

Hi Charles,

With my skills and experience I should be able to create something useful out of that sequence of hexadecimal numbers in your message. But for most reader I guess it would be much easier if you just attached a ready to use syx file, including header, checksum and eox, as a binary attachment. Does this mailinglist allow attachments?

Martin

Op dinsdag 1 april 2025 om 21:19:36 -04:00:00 schreef charles via groups.io <charles.copp@...>:

headerless vced voice , my new dx atari program "voice creator" coming along fine... any features or function suggestions please reccomend.. atm its alot of random creation stuff.. heres a nice voice , which surprisingly sounds good using any algorithm wont work if you dont add the header,checksum and end of exclusive bytes 2F 15 2F 2D 4E 17 55 32 00 00 00 00 00 00 00 00 60 01 04 5C 02 40 10 2B 23 2C 2D 1A 2E 00 00 00 00 00 00 00 00 60 01 09 4E 08 51 48 09 21 60 40 54 63 00 00 00 00 00 00 00 00 62 01 09 00 02 56 63 35 3E 02 44 43 00 00 00 00 00 00 04 00 00 5F 00 08 00 05 5F 5E 57 49 52 09 55 00 00 00 00 00 00 02 00 00 5D 00 02 00 0E 53 53 41 4B 09 3F 48 00 00 00 00 00 00 00 00 00 60 00 01 00 02 63 63 63 63 32 32 32 32 08 07 00 4F 03 20 00 00 05 00 18 6E 22 5E 25 7A 79 2C 55 68 37 30 charles /|\??♀


headerless vced new voice

 

headerless vced voice ,

my new dx atari program "voice creator" coming along fine...

any features or function suggestions please reccomend..

atm its alot of random creation stuff..

heres a nice voice , which surprisingly sounds good using any algorithm


wont work if you dont add the header,checksum and end of exclusive bytes

2F 15 2F 2D 4E 17 55 32 00 00 00 00 00 00 00 00 60 01 04 5C 02 40 10 2B 23 2C 2D 1A 2E
00 00 00 00 00 00 00 00 60 01 09 4E 08 51 48 09 21 60 40 54 63 00 00 00 00 00 00 00 00 62
01 09 00 02 56 63 35 3E 02 44 43 00 00 00 00 00 00 04 00 00 5F 00 08 00 05 5F 5E 57 49 52
09 55 00 00 00 00 00 00 02 00 00 5D 00 02 00 0E 53 53 41 4B 09 3F 48 00 00 00 00 00 00 00
00 00 60 00 01 00 02 63 63 63 63 32 32 32 32 08 07 00 4F 03 20 00 00 05 00 18 6E 22 5E 25
7A 79 2C 55 68 37 30


charles /|\??♀


Re: Yamaha DX1 battery replacement

 

I *really* need to change the battery in mine.? I've had it for...36 years?? Don't remember when they came out...

Eldred

On Sat, Mar 29, 2025 at 12:04?PM `Burns via <Burnsievt=[email protected]> wrote:

Given the batteries are kind of good for about 15 years, it’s ironic that I just took my DX7 down to put in a new battery.

?

What are the chances?

?

I think I put a holder in last time.

?

From: [email protected] <[email protected]> On Behalf Of Booking via
Sent: Saturday, March 29, 2025 12:03 PM
To: Don Backshall <backshall1@...>; [email protected]
Subject: Re: [YamahaDX] Yamaha DX1 battery replacement

?

Thanks to both of you.?

I’ll do as you suggested: open the DX1 get a battery holder and replace the battery with the same one.?






--
Reading can seriously damage your ignorance...


Re: Yamaha DX1 battery replacement

 

开云体育

Given the batteries are kind of good for about 15 years, it’s ironic that I just took my DX7 down to put in a new battery.

?

What are the chances?

?

I think I put a holder in last time.

?

From: [email protected] <[email protected]> On Behalf Of Booking via groups.io
Sent: Saturday, March 29, 2025 12:03 PM
To: Don Backshall <backshall1@...>; [email protected]
Subject: Re: [YamahaDX] Yamaha DX1 battery replacement

?

Thanks to both of you.?

I’ll do as you suggested: open the DX1 get a battery holder and replace the battery with the same one.?


Re: Yamaha DX1 battery replacement

 

Thanks to both of you.?

I’ll do as you suggested: open the DX1 get a battery holder and replace the battery with the same one.?


Re: Yamaha DX1 battery replacement

 

开云体育

CR2032 is a generic battery number without solder tabs. Most likely, the DX1 has a soldered-in battery that requires the correct solder tabs on the battery. Syntaur should know what fits properly, Alternately, you could solder in a 2032 battery holder and use a battery without solder tabs. You should open the DX1 and make sure the battery looks like the one in Syntaur's photo.

Don Backshall

On 3/29/2025 3:52 AM, Booking via groups.io wrote:

Hi all,
?
the battery of my DX1 appears to be dead. The service manual states that it should be replaced with a CR2032. By looking at this link Syntaur states a BR2325.
?
Which one should I use?
?
Thanks!
?
?




Re: Yamaha DX1 battery replacement

 

开云体育

as long as the soldering lugs fit and it?s a 3V battery,- it doesn?t matter IMO.

The batteries in my TX-816 and in all my other Yamaha gear from that time are all CR2032.
Meanwhile, I use battery holders for CR2032.

The nomenclature is just only international standard installation size (diameter/thickness).

To be sure,- I?d open the DX1 and have a look what?s in.

Am 29.03.2025 um 08:52 schrieb Booking via groups.io:
Hi all,
?
the battery of my DX1 appears to be dead. The service manual states that it should be replaced with a CR2032. By looking at this link Syntaur states a BR2325.
?
Which one should I use?
?
Thanks!
?

Virenfrei.


Yamaha DX1 battery replacement

 

Hi all,
?
the battery of my DX1 appears to be dead. The service manual states that it should be replaced with a CR2032. By looking at this link Syntaur states a BR2325.
?
Which one should I use?
?
Thanks!
?
?

yamaha_DX1_battery_service_manual.jpg
yamaha_DX1_battery_syntaur.jpg


Re: yamaha dx7ii fd internal character set

 

Well, that depends on the CGROM font table in the LCD and how consistent Yamaha was over the years with their specs and procurement. There are certainly characters above 127, but they are an order-able character set from the LCD vendor (or more correctly the HD44780 vendor which is probably Hitachi or other Japanese).

Download the Hitachi data book that has the HD44780 and/or HD44780A (or even the HD44780U LCD-II)? in it. That's your starting point.

GB

On 3/23/2025 8:40 AM, charles via groups.io wrote:
ok sounds like good advice.....
i was actually hoping there would be some hidden characters in the dx to use ,however no none, except the yen symbol...and couple arrows? ? lol

this is bit off topic but? i had no clue this guy passed away
im still trying to find alot of his atari software and code



Re: yamaha dx7ii fd internal character set

 

ok sounds like good advice.....
?
i was actually hoping there would be some hidden characters in the dx to use ,however no none, except the yen symbol...and couple arrows? ? lol

this is bit off topic but? i had no clue this guy passed away
im still trying to find alot of his atari software and code
?
https://www.soundonsound.com/news/martin-russ-obituary?


Re: yamaha dx7ii fd internal character set

 

In the software I created for my Yamaha synths I limit my characters to the 32-127 range. That's what I did in my Atari projects, and today in my Python projects on newer computers.

groeten,
Martin


-------- Oorspronkelijk bericht --------
Onderwerp: [YamahaDX] yamaha dx7ii fd internal character set
Van: "charles via groups.io"
Aan: [email protected]
Cc:


im still using my trusty atari and have written a dx7 voice editor ..anyone can save me some time and point me to a description of the dx7 character set?? ?its not completely compatible with ascii.?
but i am only permitted to use character value 0-127?? ?
charles


Re: yamaha dx7ii fd internal character set

 
Edited

ok so i went right to work after my first post to correspond values dx<->atari?

this is my finding?
?
left column is 7bit# sent to dx?
right column is description of character displayed on dx screen.
?
0=freq symbol? 'f'?
1=time symbol 't'
2-7=? four stacked horizontal line?
8=f again!
9=t again??
10-31 blank? = space?
32-91 exactly same as atari ascii character set
92= something resembling power line beacon ???? yen?
93-125 exactly same as atari ascii character set
126=arrow right
127=arrow left
?
?
so the only real world correlation would be:
if your dx names are in capital letters then they were made with a dx7 software voice editor.
?
my dx7iifd does not permit me to enter capital letters unless using a software editor......???


Re: yamaha dx7ii fd internal character set

 

not sure but this might be it?

The sysex format won't let you send values greater than 127.

Op za 22 mrt 2025 om 22:48 schreef charles via <charles.copp=[email protected]>:

im still using my trusty atari and have written a dx7 voice editor ..anyone can save me some time and point me to a description of the dx7 character set?? ?its not completely compatible with ascii.?
but i am only permitted to use character value 0-127?? ?
charles




yamaha dx7ii fd internal character set

 

im still using my trusty atari and have written a dx7 voice editor ..anyone can save me some time and point me to a description of the dx7 character set?? ?its not completely compatible with ascii.?
but i am only permitted to use character value 0-127?? ?
charles


Re: DX patches

 

To all members, I thank you for your insights and suggestions.
Please feel free to update me if you come across anything else that would help.
?
Best regards
?


Re: DX patches

 

开云体育

Just a simple hint: if your are looking for something from a dedicated culture, then search like if you'd be from that culture: Use translate.google.com or deepl.com or similar, translate your request to the corresponding language and do the search.
Of course your results will be in the same language, so it will be a lot of translation effort then - but I was really successful with this method.

And of course don't search for "arabian DX-7 sounds" but instead look for "Oud or Bouzouki as DX-7 sound".
You never would search for a "american steel guitar sound", because americans never would mention their own culture within that search.


Florian

Am 15.02.25 um 13:55 schrieb Daniel Forró via groups.io:

I collect DX7 patches since 1986, but never found any Near East, Arabian, Turkish, Iranian, Greek, Balkan… patch.

The only ethnic patches I know are African, Indian, Chinese, Japanese, Indonesian, Jamaican, and some European (accordions, recorder, bag-pipes, fiddle, hurdy-gurdy, some percussions).

It wouldn’t be easy to program those Oriental patches on DX7. 

But I know some Balkan musicians used DX11, and Casio CZ successfully for imitation of some folk instruments.

If you need them, find some sampler or sample based synthesizer or arranger keyboard specialized on this type of sounds (and even styles), like Yamaha PSR1000, Korg PA80 with Turkish card or so. 

Daniel Forró



On Feb 15, 2025, at 16:37, tsoukoulis via groups.io <tsoukoulis@...> wrote:

Thanks for that Nick, 

I have played around with these in the past with limited success.
Also finding it difficult to switch quickly from one patch to another within a suitable time frame - whereas performance patches can be changed relatively quickly.

If possible I am looking for patches akin to Yamaha PSRa 5000 "Istanbul Strings, OUD - etc World Instruments" Suitable for the DX7 - ???

I am open to further suggestions

PS I'm not very tech savvy ... I know just enough to get by LOL......

Cheers 





      




Re: DX patches

 

Hi,

DX7 wasn't really a synth of choice in the Balkan ethno-music. DX21, DX11 and V50, Casio CZ101 and later the SY77 were the most used ones. I have Balkan patches for DX21, DX11 and V50 lying around, but I couldn't test them, so I can't judge the quality. I should also have a bank or two of DX7/DX7II Balkan patches. I've bought recently a TX81z, and I could theoretically test these patches and do some selection, but I am in the middle of renovating my apartment, and all my equipment is packed in the basement at the moment.

There is also a Romanian web-forum, offering some DX and V50 patches, but you need to buy premium membership to download files. They have a loooot of sampled voices for newer sample-based keyboards (Genos, Tyros, PSR-S..., PSR-A...)


regards

Boban


Am 15.02.2025 um 13:55 schrieb Daniel Forró via groups.io:

I collect DX7 patches since 1986, but never found any Near East, Arabian, Turkish, Iranian, Greek, Balkan… patch.

The only ethnic patches I know are African, Indian, Chinese, Japanese, Indonesian, Jamaican, and some European (accordions, recorder, bag-pipes, fiddle, hurdy-gurdy, some percussions).

It wouldn’t be easy to program those Oriental patches on DX7.

But I know some Balkan musicians used DX11, and Casio CZ successfully for imitation of some folk instruments.

If you need them, find some sampler or sample based synthesizer or arranger keyboard specialized on this type of sounds (and even styles), like Yamaha PSR1000, Korg PA80 with Turkish card or so.

Daniel Forró



On Feb 15, 2025, at 16:37, tsoukoulis via groups.io <tsoukoulis@...> wrote:

Thanks for that Nick,

I have played around with these in the past with limited success.
Also finding it difficult to switch quickly from one patch to another within a suitable time frame - whereas performance patches can be changed relatively quickly.

If possible I am looking for patches akin to Yamaha PSRa 5000 "Istanbul Strings, OUD - etc World Instruments" Suitable for the DX7 - ???

I am open to further suggestions

PS I'm not very tech savvy ... I know just enough to get by LOL......

Cheers




Re: DX patches

 

I collect DX7 patches since 1986, but never found any Near East, Arabian, Turkish, Iranian, Greek, Balkan… patch.

The only ethnic patches I know are African, Indian, Chinese, Japanese, Indonesian, Jamaican, and some European (accordions, recorder, bag-pipes, fiddle, hurdy-gurdy, some percussions).

It wouldn’t be easy to program those Oriental patches on DX7.

But I know some Balkan musicians used DX11, and Casio CZ successfully for imitation of some folk instruments.

If you need them, find some sampler or sample based synthesizer or arranger keyboard specialized on this type of sounds (and even styles), like Yamaha PSR1000, Korg PA80 with Turkish card or so.

Daniel Forró

On Feb 15, 2025, at 16:37, tsoukoulis via groups.io <tsoukoulis@...> wrote:

Thanks for that Nick,

I have played around with these in the past with limited success.
Also finding it difficult to switch quickly from one patch to another within a suitable time frame - whereas performance patches can be changed relatively quickly.

If possible I am looking for patches akin to Yamaha PSRa 5000 "Istanbul Strings, OUD - etc World Instruments" Suitable for the DX7 - ???

I am open to further suggestions

PS I'm not very tech savvy ... I know just enough to get by LOL......

Cheers