Everything related to Yamaha DX/TX family of synths
/g/YamahaDX
Continuation of the YamahaDX and YamahaDXFiles groups from Yahoo!
Currently awaiting the import of all data from Yahoo group YamahaDX.
Active since Nov 1999.Wed, 17 Nov 1999 08:00:35 -0800Re: headerless vced new voice
/g/YamahaDX/message/21057
<html><head><meta http-equiv="content-type"/></head><body><p>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)</p><p>Claude.ai:</p><p>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.</p><p>From the documents, I can see:</p><ol><li>A detailed description of the DX7 envelope logic in the PDF</li><li>C++ implementation code in the env.cc.rtf file</li></ol><p>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.</p><p>Here's my approach to rebuild the interactive diagram:</p><ol><li>First, I'll create an HTML structure with SVG for the envelope visualization</li><li>Implement the core envelope calculation logic from the C++ code</li><li>Add interactive controls for the envelope parameters</li><li>Connect the controls to update the visualization in real-time</li></ol><p>Let me create this as a single HTML file with embedded JavaScript:</p><pre><code class="language-html"><!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>
</code></pre><p>This interactive diagram of the Yamaha DX7 envelope implements the core logic from the provided documents. Here's what I've created:</p><ol><li><p><strong>Visual representation</strong>: An SVG graph that shows the envelope shape with proper scaling for both amplitude and time.</p></li><li><p><strong>Parameter controls</strong>: Sliders for all the key DX7 envelope parameters:</p><ul><li>Rates (R1-R4): Control how quickly the envelope moves between stages</li><li>Levels (L1-L4): Define the amplitude at each stage</li><li>Output Level: Overall amplitude scaling</li><li>Rate Scaling: Parameter that affects envelope timing</li></ul></li><li><p><strong>Real-time animation</strong>: A simulation that shows how the envelope progresses in real-time, including:</p><ul><li>A trigger button to start the envelope</li><li>A release button to enter the release phase</li><li>A position marker showing the current point on the envelope</li></ul></li><li><p><strong>Accurate timing calculations</strong>: The code implements the DX7's distinctive envelope timing calculations based on the C++ implementation, including:</p><ul><li>Level scaling using the lookup table for low values</li><li>Rate calculations with proper quantization</li><li>Attack/decay curve characteristics</li></ul></li></ol><p>To use the diagram:</p><ol><li>Adjust the sliders to modify the envelope shape</li><li>Click "Trigger Note" to see the envelope in action</li><li>Click "Release Note" to hear how the release phase sounds</li></ol><p>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?</p><p><br/></p><p>Maybe someone has a better grip on AI. I didn’t get closer with the next prompts.</p><p><br/></p><p>Here is what I could find about the envelope:</p><p style="margin: 0px 0px 7px; font-style: normal; line-height: normal"><b><font face="HelveticaNeue">DX7 Envelope</font></b></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">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. </font></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">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). </font></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">The conversion from level parameter (L1, L2, L3, L4 in the patch) to actual level is as follows: </font></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">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,]. </font></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">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 log<span style="font-style: normal; line-height: normal"><sub>10</sub></span>(2) / 256), so that 256 of these steps doubles the amplitude. </font></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">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. </font></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">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. </font></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">The rate of decay is then 0.2819 `*` 2<span style="font-style: normal; line-height: normal"><sup>(qrate / 4)</sup></span> `*` (1 + 0.25 `*` (qrate mod 4)) dB/s. This is a reasaonably good approximation to 0.28 `*` 2<span style="font-style: normal; line-height: normal"><sup>(qrate `*` 0.25)</sup></span>. </font></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">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. </font></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">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. </font></p><p style="margin: 0px 0px 9px; font-style: normal; line-height: normal"><font face="HelveticaNeue">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). </font></p><p style="margin: 0px 0px 7px; font-style: normal; line-height: normal"><b><font face="HelveticaNeue">DX 7 Hardware</font></b></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">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). </font></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">At a qrate of 0, the amplitude decreases by one step every 4096 samples, in other words halves every 2<span style="font-style: normal; line-height: normal"><sup>20</sup></span> 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: </font></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal"><font face="HelveticaNeue">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. </font></p><p style="margin: 0px 0px 12px; font-style: normal; font-size: 11px; line-height: normal; font-family: Times"><br/></p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal; font-family: Times; font-size: 14px">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..</p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal; font-family: Times; font-size: 14px">Benjamin</p><p style="margin: 0px 0px 12px; font-style: normal; line-height: normal; font-family: Times; font-size: 14px">(This one is a though puzzle..)</p><p style="margin: 0px 0px 12px; font-style: normal; font-size: 11px; line-height: normal; font-family: Times"><br/></p><p><br/></p>wildjamin@... (Benjamin Wild)Wed, 02 Apr 2025 02:24:17 -0700Re: headerless vced new voice
/g/YamahaDX/message/21056
<html><head><meta http-equiv="content-type"/></head><body>It’s a riddle/puzzle to solve.. -> makes it more interesting than just another patch.<div><br/></div><div>What I thought of was: it would be very cool, if one could copy and reorganize branches of patches:</div><div>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.</div><div>(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..)</div><div><br/></div><div>Also the usability would be(was) very important to me:</div><div>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.</div><div><br/></div><div>(I tried to display the envelopes in a realistic way:</div><div><div style="display: block"><div style="display: inline-block" class="apple-rich-link"><a style="border-radius: 10px; font-family: Helvetica, Arial, sans-serif; display: block; width: 300px; text-decoration: none" class="lp-rich-link" rel="nofollow noopener" href="https://github.com/google/music-synthesizer-for-android/blob/master/wiki/Dx7Envelope.wiki" dir="ltr" target="_blank" target="_blank"><table class="lp-rich-link-emailBaseTable" width="300"><tbody><tr><td align="center"><img style="width: 300px; height: 150px" width="300" height="150" class="lp-rich-link-mediaImage myimg-responsive" alt="music-synthesizer-for-android.png" src="/g/YamahaDX/attachment/21056/0" loading="lazy"/></td></tr><tr><td><table width="300" class="lp-rich-link-captionBar"><tbody><tr><td class="lp-rich-link-captionBar-textStackItem"><div style="max-width: 100%; margin: 0px 16px 0px 16px" class="lp-rich-link-captionBar-textStack"><div style="font-weight: 500; font-size: 12px; text-align: left" class="lp-rich-link-captionBar-textStack-topCaption-leading"><a rel="nofollow noopener" href="https://github.com/google/music-synthesizer-for-android/blob/master/wiki/Dx7Envelope.wiki" style="text-decoration: none" target="_blank" target="_blank"><font color="#272727">music-synthesizer-for-android/wiki/Dx7Envelope.wiki at master · google/music-synthesizer-for-android</font></a></div><div style="font-weight: 400; font-size: 11px; text-align: left" class="lp-rich-link-captionBar-textStack-bottomCaption-leading"><a rel="nofollow noopener" href="https://github.com/google/music-synthesizer-for-android/blob/master/wiki/Dx7Envelope.wiki" style="text-decoration: none" target="_blank" target="_blank"><font color="#808080">github.com</font></a></div></div></td></tr></tbody></table></td></tr></tbody></table></a></div></div><br/></div><div> the link of the interactive dx envelope is broken there (as information seemed disappearing back then, but still here:</div><div><div style="display: block"><div style="display: inline-block" class="apple-rich-link"><a style="border-radius: 10px; font-family: Helvetica, Arial, sans-serif; display: block; width: 300px; text-decoration: none" class="lp-rich-link" rel="nofollow noopener" href="https://levien.com/dx7-envelope.html" dir="ltr" target="_blank" target="_blank"><table class="lp-rich-link-emailBaseTable" width="300"><tbody><tr><td><table width="300" class="lp-rich-link-captionBar"><tbody><tr><td class="lp-rich-link-captionBar-textStackItem"><div style="max-width: 100%; margin: 0px 16px 0px 16px" class="lp-rich-link-captionBar-textStack"><div style="font-weight: 400; font-size: 11px; text-align: left" class="lp-rich-link-captionBar-textStack-bottomCaption-leading"><a rel="nofollow noopener" href="https://levien.com/dx7-envelope.html" style="text-decoration: none" target="_blank" target="_blank"><font color="#808080">levien.com</font></a></div></div></td><td class="lp-rich-link-captionBar-rightIconItem" width="36"><a rel="nofollow noopener" href="https://levien.com/dx7-envelope.html" target="_blank"><img style="display: inline-block; width: 36px; height: 36px; border-radius: 3px" width="36" height="36" class="lp-rich-link-captionBar-rightIcon myimg-responsive" alt="favicon1.ico" src="/g/YamahaDX/attachment/21056/1" loading="lazy"/></a></td></tr></tbody></table></td></tr></tbody></table></a></div><br/></div></div><div>)</div><div><br/></div><div><br/></div><div>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:</div><div>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)</div><div><br/></div><div>Greetings from Hamburg,</div><div>Benjamin</div><div><br/></div><div>Ps. I’m trying to get a working Atari again (so I’m a bit curious about programming it too)</div><div><div></div></div>wildjamin@... (Benjamin Wild)Wed, 02 Apr 2025 01:43:52 -0700Re: headerless vced new voice
/g/YamahaDX/message/21055
<div id="geary-body"><div>Hi Charles,</div><div><br/></div><div>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?</div><div><br/></div><div>Martin</div></div><div id="geary-quote"><br/>Op dinsdag 1 april 2025 om 21:19:36 -04:00:00 schreef charles via groups.io <charles.copp@...>:<br/></div>m.tarenskeen@... (Martin Tarenskeen)Wed, 02 Apr 2025 00:17:47 -0700headerless vced new voice
/g/YamahaDX/message/21054
headerless vced voice ,<br /><br />my new dx atari program "voice creator" coming along fine...<br /><br />any features or function suggestions please reccomend..<br /><br />atm its alot of random creation stuff..<br /><br /> heres a nice voice , which surprisingly sounds good using any algorithm<br /><br /><br />wont work if you dont add the header,checksum and end of exclusive bytes<br /><br />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<br />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<br /> 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<br /> 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<br />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<br />7A 79 2C 55 68 37 30<br /><br /><br />charles /|\♪♫♀charles.copp@... (charles)Tue, 01 Apr 2025 18:19:38 -0700Re: Yamaha DX1 battery replacement
/g/YamahaDX/message/21053
<div dir="ltr"><div class="gmail_default" style="font-family: arial, helvetica, sans-serif">I *really* need to change the battery in mine. I've had it for...36 years? Don't remember when they came out...</div><div class="gmail_default" style="font-family: arial, helvetica, sans-serif"><br/></div><div class="gmail_default" style="font-family: arial, helvetica, sans-serif">Eldred</div></div><br/>epickett@... (Eldred Pickett)Sat, 29 Mar 2025 16:35:27 -0700Re: Yamaha DX1 battery replacement
/g/YamahaDX/message/21052
<html><head><meta http-equiv="Content-Type"/><meta name="Generator"/></head><body lang="EN-US"><div class="WordSection1"><p class="MsoNormal"><span style="font-family: sans-serif">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. </span></p><p class="MsoNormal"><span style="font-family: sans-serif"> </span></p><p class="MsoNormal"><span style="font-family: sans-serif">What are the chances?</span></p><p class="MsoNormal"><span style="font-family: sans-serif"> </span></p><p class="MsoNormal"><span style="font-family: sans-serif">I think I put a holder in last time. </span></p><p class="MsoNormal"><span style="font-family: sans-serif"> </span></p><div style="border: none; border-top: solid #E1E1E1 1.0pt"><p class="MsoNormal"></p></div></div>Burnsievt@... (`Burns)Sat, 29 Mar 2025 09:04:49 -0700Re: Yamaha DX1 battery replacement
/g/YamahaDX/message/21051
<div>Thanks to both of you. <br/><br/></div>
<div>I’ll do as you suggested: open the DX1 get a battery holder and replace the battery with the same one. </div>registerbooking@... (Booking)Sat, 29 Mar 2025 09:02:47 -0700Re: Yamaha DX1 battery replacement
/g/YamahaDX/message/21050
<html><head><meta http-equiv="Content-Type"/>
</head><body>
<p>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.</p>
<p>Don Backshall<br/>
</p>
<div class="moz-cite-prefix">On 3/29/2025 3:52 AM, Booking via
groups.io wrote:<br/>
</div>
backshall1@... (Don Backshall)Sat, 29 Mar 2025 08:21:37 -0700Re: Yamaha DX1 battery replacement
/g/YamahaDX/message/21049
<html><head><meta http-equiv="Content-Type"/>
</head><body>
as long as the soldering lugs fit and it´s a 3V battery,- it doesn´t
matter IMO.<br/>
<br/>
The batteries in my TX-816 and in all my other Yamaha gear from that
time are all CR2032.<br/>
Meanwhile, I use battery holders for CR2032.<br/>
<br/>
The nomenclature is just only international standard installation
size (diameter/thickness).<br/>
<br/>
To be sure,- I´d open the DX1 and have a look what´s in.<br/>
<br/>
<div class="moz-cite-prefix">Am 29.03.2025 um 08:52 schrieb Booking
via groups.io:<br/>
</div>
<blockquote cite="mid:[email protected]">
<meta http-equiv="content-type"/>
<div>Hi all,</div>
<div>Â </div>
<div>the battery of my DX1 appears to be dead. The service manual
states that it should be replaced with a <strong>CR2032</strong>.
By looking at this link <a href="https://syntaur.com/Part-2259-Battery-3V-Lithium" target="_blank" class="moz-txt-link-freetext" rel="nofollow noopener">https://syntaur.com/Part-2259-Battery-3V-Lithium</a>
Syntaur states a <strong>BR2325</strong>.</div>
<div>Â </div>
<div>Which one should I use?</div>
<div>Â </div>
<div>Thanks!</div>
<div>Â <br/>
</div>
</blockquote>
<div id="DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2"><br/><table><tbody><tr><td><a href="https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient" target="_blank" rel="nofollow noopener"><img src="https://s-install.avcdn.net/ipm/preview/icons/icon-envelope-tick-round-orange-animated-no-repeat-v1.gif" alt="" width="46" height="29" style="width: 46px; height: 29px" loading="lazy" class="myimg-responsive"/></a></td><td>Virenfrei.<a href="https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient" target="_blank" style="color: #4453ea" rel="nofollow noopener">www.avast.com</a></td></tr></tbody></table><a href="#DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2" rel="nofollow noopener" target="_blank"> </a></div>
ha-pewe@... (PeWe)Sat, 29 Mar 2025 08:21:07 -0700Yamaha DX1 battery replacement
/g/YamahaDX/message/21048
<div>Hi all,</div>
<div>Â </div>
<div>the battery of my DX1 appears to be dead. The service manual states that it should be replaced with a <strong>CR2032</strong>. By looking at this link <a href="https://syntaur.com/Part-2259-Battery-3V-Lithium" target="_blank" rel="nofollow noopener">https://syntaur.com/Part-2259-Battery-3V-Lithium</a> Syntaur states a <strong>BR2325</strong>.</div>
<div>Â </div>
<div>Which one should I use?</div>
<div>Â </div>
<div>Thanks!</div>
<div>Â </div>
<div>Â </div>registerbooking@... (Booking)Sat, 29 Mar 2025 07:54:44 -0700Re: yamaha dx7ii fd internal character set
/g/YamahaDX/message/21047
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).<br /><br />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.<br /><br />GBgrantbt@... (grantpbt)Sun, 23 Mar 2025 09:21:03 -0700Re: yamaha dx7ii fd internal character set
/g/YamahaDX/message/21046
<div>ok sounds like good advice.....</div>
<div>Â </div>
<div>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<br/><br/>this is bit off topic but i had no clue this guy passed away</div>
<div>im still trying to find alot of his atari software and code</div>
<div>Â </div>
<div>https://www.soundonsound.com/news/martin-russ-obituary </div>charles.copp@... (charles)Sun, 23 Mar 2025 08:40:25 -0700Re: yamaha dx7ii fd internal character set
/g/YamahaDX/message/21045
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.<br/><br/>groeten,<br/>Martin<div class="quote" style="line-height: 1.5"><br/><br/>-------- Oorspronkelijk bericht --------<br/>Onderwerp: [YamahaDX] yamaha dx7ii fd internal character set<br/>Van: "charles via groups.io" <br/>Aan: [email protected]<br/>Cc: <br/><br/><br/></div>m.tarenskeen@... (Martin Tarenskeen)Sat, 22 Mar 2025 23:58:56 -0700Re: yamaha dx7ii fd internal character set
/g/YamahaDX/message/21044
<div>ok so i went right to work after my first post to correspond values dx<->atari </div>
<div><br/>this is my finding </div>
<div>Â </div>
<div>left column is 7bit# sent to dx </div>
<div>right column is description of character displayed on dx screen.</div>
<div>Â </div>
<div>0=freq symbol 'f'ƒ</div>
<div>1=time symbol 't'</div>
<div>2-7=Â four stacked horizontal line?</div>
<div>8=f again!</div>
<div>9=t again? </div>
<div>10-31 blank = space?</div>
<div>32-91 exactly same as atari ascii character set</div>
<div>92= something resembling power line beacon ??? yen?</div>
<div>93-125 exactly same as atari ascii character set</div>
<div>126=arrow right</div>
<div>127=arrow left</div>
<div>Â </div>
<div>Â </div>
<div>so the only real world correlation would be:</div>
<div>if your dx names are in capital letters then they were made with a dx7 software voice editor.</div>
<div>Â </div>
<div>my dx7iifd does not permit me to enter capital letters unless using a software editor......?? </div>charles.copp@... (charles)Sat, 22 Mar 2025 15:45:04 -0700Re: yamaha dx7ii fd internal character set
/g/YamahaDX/message/21043
<div dir="ltr"><div><a href="https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller#Font" rel="nofollow noopener" target="_blank">https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller#Font</a> not sure but this might be it?</div><div><br/></div><div>The sysex format won't let you send values greater than 127.</div></div><br/><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">Op za 22 mrt 2025 om 22:48 schreef charles via <a href="http://groups.io" rel="nofollow noopener" target="_blank">groups.io</a> <charles.copp=<a href="mailto:[email protected]" rel="nofollow noopener" target="_blank">[email protected]</a>>:<br/></div></div>contact@...Sat, 22 Mar 2025 15:05:07 -0700yamaha dx7ii fd internal character set
/g/YamahaDX/message/21042
<div>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. <br/>but i am only permitted to use character value 0-127?  </div>
<div>charles</div>charles.copp@... (charles)Sat, 22 Mar 2025 14:48:49 -0700Re: DX patches
/g/YamahaDX/message/21041
<div>To all members, I thank you for your insights and suggestions.</div>
<div>Please feel free to update me if you come across anything else that would help.</div>
<div>Â </div>
<div>Best regards</div>
<div>Â </div>tsoukoulis@...Sat, 15 Feb 2025 23:00:49 -0800Re: DX patches
/g/YamahaDX/message/21040
<html><head><meta http-equiv="Content-Type"/>
</head><body>
<div class="moz-cite-prefix">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.<br/>
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.<br/>
<br/>
And of course don't search for "arabian DX-7 sounds" but instead
look for "Oud or Bouzouki as DX-7 sound". <br/>
You never would search for a "american steel guitar sound",
because americans never would mention their own culture within
that search.<br/>
<br/>
<br/>
Florian<br/>
<br/>
Am 15.02.25 um 13:55 schrieb Daniel Forró via groups.io:<br/>
</div>
fanwander@... (Florian Anwander)Sat, 15 Feb 2025 11:59:01 -0800Re: DX patches
/g/YamahaDX/message/21039
Hi,<br /><br />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.<br /><br />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...)<br /><br /><br />regards<br /><br />Boban<br /><br /><br />Am 15.02.2025 um 13:55 schrieb Daniel Forró via groups.io:spasic@... (Spasic)Sat, 15 Feb 2025 05:43:21 -0800Re: DX patches
/g/YamahaDX/message/21038
I collect DX7 patches since 1986, but never found any Near East, Arabian, Turkish, Iranian, Greek, Balkan� patch.<br /><br />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).<br /><br />It wouldn’t be easy to program those Oriental patches on DX7. <br /><br />But I know some Balkan musicians used DX11, and Casio CZ successfully for imitation of some folk instruments.<br /><br />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. <br /><br />Daniel Forródanforcz@... (Daniel Forró)Sat, 15 Feb 2025 04:55:26 -0800