nodejs:midi-writer-js 将基金净值数据转换为 midi 文件

开放式基金是没有公布每日交易量的。

/funds/data/660008.csv 文件开头:
date,jz,ljjz
2016-01-04,1.1141,1.1141
2016-01-05,1.1161,1.1161
2016-01-06,1.1350,1.1350

这是一个将开放式基金数据转换为 MIDI音乐的 js 程序示例。该程序将基金净值映射为 MIDI音符的音高

mkdir test-midi
cd test-midi
npm init -y 
cnpm install csv-parser -S
cnpm install midi-writer-js -S

编写 fund2midi.js  如下

// fund2midi.js
const fs = require('fs');
const csv = require('csv-parser');
const MidiWriter = require('midi-writer-js');

// 参数验证
const args = process.argv.slice(2);
if (args.length !== 1 || args[0].length !== 6) {
    console.log('用法: node fund2midi.js <6位基金代码>');
    process.exit(1);
}

const fcode = args[0];
const csvFile = `/funds/data/${fcode}.csv`;
const outputFile = `melo_${fcode}.mid`;

// 读取并处理CSV数据
async function processData() {
    const results = [];

    return new Promise((resolve, reject) => {
        fs.createReadStream(csvFile)
           .pipe(csv())
           .on('data', (data) => {
                if (data.date > '2024-01-01') {
                    results.push({
                        date: data.date,
                        jz: parseFloat(data.jz)
                    });
                }
            })
           .on('end', () => {
                if (results.length < 20) {
                    console.log(`${results.length} < 20`);
                    process.exit(2);
                }
                resolve(results);
            })
           .on('error', reject);
    });
}

// 生成MIDI文件
function generateMIDI(prices) {
    const track = new MidiWriter.Track();
    track.setTempo(120);

    // 数据归一化
    const minPrice = Math.min(...prices);
    const maxPrice = Math.max(...prices);
    const priceRange = maxPrice - minPrice;

    // 计算音符范围
    let minNote = 48; // C3
    let maxNote = 84; // C5
    if ((maxPrice / minPrice) < (84.0/48.0)) {
        maxNote = Math.round(50 * (maxPrice / minPrice));
    }
    if (maxNote % 2 === 1) maxNote++;

    prices.forEach(price => {
        const pitch = (priceRange < 0.001)
            ? Math.round((maxNote + minNote) / 2)
            : minNote + Math.round(((price - minPrice) / priceRange) * (maxNote - minNote));

        const note = new MidiWriter.NoteEvent({
            pitch: [pitch],
            duration: '4',
            velocity: 63   // 音量: 63% *127 = 80
        });
        track.addEvent(note);
    });

    // 直接在构造函数中传入轨道数组
    const writer = new MidiWriter.Writer([track]);
    return writer;
}

// 主流程
(async () => {
    try {
        const data = await processData();
        const prices = data.map(d => d.jz);

        console.log(`基金代码: ${fcode}`);
        console.log(`数据量: ${prices.length}`);
        console.log(`最大值: ${Math.max(...prices)}`);
        console.log(`最小值: ${Math.min(...prices)}`);

        const midi = generateMIDI(prices);
        fs.writeFileSync(outputFile, midi.buildFile(), 'binary');
        console.log(`生成成功: ${outputFile}`);
    } catch (err) {
        console.error('发生错误:', err.message);
        process.exit(1);
    }
})();

运行 node fund2midi.js 660008 
生成 melo_660008.mid

运行 python play_mid.py melo_660008.mid 

运行 python mido_msg.py melo_660008.mid 查看 midi文件内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值