Open fornof opened 1 year ago
update: Fixed it. the ES6/Typescript import is broken somehow. using require works fine. This is my working example for typescript.
import {promises as fs} from 'fs'
var JZZ = require('jzz')
var SMF = require('jzz-midi-smf')
let testFile = await fs.readFile("test/data/testScale1.mid", "binary")
var midiout = JZZ().openMidiOut(); //I think this is just for player.play()
var smf = new JZZ.MIDI.SMF(testFile);
var player = smf.player();
player.connect(midiout);
//player.play();
fs.writeFile('test/data/out.mid', smf.dump(), 'binary');
I am using TypeScript in my project and have encountered the same problem. The require() solution however unfortunately does not work for me.
var JZZ = require('jzz') works fine but var SMF = require('jzz-midi-smf') throws Could not find a declaration file for module 'jzz-midi-smf'. I assume because index.d.ts is missing. I know it is a lot of work to convert the js to TS but is there some online generator to do it?
Use this for smf , rest of the code is above, ignore the smf import
var smf = new JZZ.MIDI.SMF(testFile);
I now get
Property 'SMF' does not exist on type 'Constructor'. Did you mean 'smf'?
I then tried var smf = JZZ.MIDI.smf();
but the var player = smf.player();
says Property 'player' does not exist on type 'MIDI'
The new keyword also did not work with/without.
Use SMF (in capitals) and ignore the warning.
I am using Svelte Kit and require does not work.
the code runs if I comment out var smf = new JZZ.MIDI.SMF();
so it can import jzz just fine. The jzz-midi-smf gives me
and SMF(); says
I assume because it is not imported correctly.\
The JZZ examples run just fine the problem is in JZZ.MIDI.SMF
Call SMF(JZZ); as shown in the example. That will add the missing member.
I still get the same error no change. I assume the error is in the import and TS can't find the package to load.
I was able to get it the typescript errors are just cosmetic.
On a different note is there a way to access the array of available midi in and out ports?
And/Or recreate this function that updates on port change to get a dropdown menu of available ports?
async initMidiPorts(){
await navigator.requestMIDIAccess()
.then((midiAccess) => {
this.midiAccess = midiAccess;
this.updateMidiOptions();
midiAccess.onstatechange = (event) => this.updateMidiOptions();
});
}
If not it is no big deal. I appreciate the work you have done on this library. I didn't see it in the docs but could revealing midiAccess.inputs.values() allow this?
You can use other libraries to get the names of midi inputs and midi outputs
for getting a list of available outputs you will need to request access to midi, then the browser gives you the inputs and outputs to you:
const midis = await navigator.requestMIDIAccess()
for (let i of midis.outputs.values()){ console.log(i)}
you will want i.name I believe.
I found a solve for in browser typescript react. It is very close to the instructions , except it needs a type.d.ts file
jzz-midi-smf.d.ts
in src/ or similar , in this file put in:
declare module 'jzz-midi-smf'
This step will give a complete running copy with a save file in the browser. Using react and vite. I wish something was on the main page for quick-start. It took me a few hours to find the docs and put everything together.
import { useEffect, useState } from 'react'
import JZZ from 'jzz'
import SMF from 'jzz-midi-smf'
import './App.css'
SMF(JZZ)
function midiPlay(smfIn: any){
const midiout = JZZ().openMidiOut([0,1,2,3,4]);
const player = smfIn.player();
console.log("dump", smfIn.dump())
player.connect(midiout);
player.play()
}
function midiToBase64Save(data: any){
//https://jazz-soft.net/demo/WriteMidiFile.html
// MIDI file dumped as a string
var b64 = JZZ.lib.toBase64(data); // convert to base-64 string
var uri = 'data:audio/midi;base64,' + b64; // data URI
//const a = document.createElement('a');
//a.href = uri;
//a.download = name||'itWorks.mid';
//a.click();
return uri
}
function midiOut(){
var smf =JZZ.MIDI.SMF(2,96); // type 0, 96 ticks per quarter note
var trk = new JZZ.MIDI.SMF.MTrk();
smf.push(trk); // add contents: trk.add(0, JZZ.MIDI.smfSeqName('This is a sequence name')) .add(0, JZZ.MIDI.smfBPM(90)) // tempo 90 bpm .add(96, JZZ.MIDI.noteOn(0, 'C6', 127)) .add(96, JZZ.MIDI.noteOn(0, 'Eb6', 127)) .add(96, JZZ.MIDI.noteOn(0, 'G6', 127)) .add(192, JZZ.MIDI.noteOff(0, 'C6')) .add(192, JZZ.MIDI.noteOff(0, 'Eb6')) .add(192, JZZ.MIDI.noteOff(0, 'G6')) .add(988, JZZ.MIDI.smfEndOfTrack());
for (var i = 0; i < smf.length; i++) { for (var j = 0; j < smf[i].length; j++) { console.log('track:', i, 'tick:', smf[i][j].tt, smf[i][j].toString()); // or do whatever else with the message } } return smf } function App() { const [fileOut, SetFileOut] = useState("")
useEffect(()=>{ const smf = midiOut() midiPlay(smf) SetFileOut(midiToBase64Save(smf.dump())) console.log("alldone!") },[]) return ( <>
</>
) }
export default App function onEffect(arg0: () => void) { throw new Error('Function not implemented.') }
You will need a midi out to hear `midiPlay()`. The output just asks for the first output it can find in 0,1,2,3,4 - I think that is what https://jazz-soft.net/doc/JZZ/midiout.html#open OpenMidiOut does anyways 🤷
another issue is that Typescript goes berserk when type at start is not type at end. I resolved with creating a type specifically for SMF which allows testing to continue with jest and not error out:
type Constructor = (typeof JZZ.MIDI)
export interface MidiConstructor extends Constructor {
SMF: Function| { MTrk: Function}| any
}
export function midiOut(){
var smf =(JZZ.MIDI as MidiConstructor).SMF(2,96); // type 0, 96 ticks per quarter note
var trk = new (JZZ.MIDI as MidiConstructor).SMF.MTrk();
...
}
I'm getting an error when I copy paste the example : Module '"jzz-midi-smf"' has no exported member 'SMF'
I did 'import JZZ from "jzz" and that gets live audio working. I could not get the jzz-midi-smf to work though.
I'm using Typescript/ Nodejs, compiling down in react and phaser and rendering to the browser. I did notice this one: https://github.com/jazz-soft/JZZ/issues/62 I might be able to help out if there is no quick solution to this.