From: Joe E. <jo...@em...> - 2005-03-08 04:38:16
|
This is making me really depressed. I'm trying.... again... to make a synthdriver. I figured I'd start with baby steps. All I wanted to do is make a driver that can receive a sysex message and dump it to the console. Before I even do *that*, I figured that I'd skip the sysex part and just try to create a blank patch and then see if I could dump it to the console. The dump is supposed to happen when I go to "Edit.." the patch. So, I made a Device class: > public class AlesisSR16Device extends Device { > > public AlesisSR16Device () { > super("Alesis", "SR-16", "000000000000000E0E000.00........f7", > "Let's see how this goes....", > "Joe Emenaker"); > } > > public AlesisSR16Device(Preferences prefs) { > this(); > this.prefs = prefs; > > addDriver (new HexDumpDriver ()); > } > } Then, I made HexDumpDriver..... > public class HexDumpDriver extends Driver { > > public HexDumpDriver() { > super("Sysex", "Joe Emenaker"); > sysexID = "F000000E13****"; > } > > public HexDumpDriver(String patchType, String authors) { > super(patchType, authors); > } > > boolean hasEditor() { > return true; > } > > protected JSLFrame editPatch(Patch p) { > SysexMessage[] messages = p.getMessages(); > for(int i=0; i<messages.length; i++) { > > System.out.println(core.Utility.hexDump(messages[i].getData(),0,-1,16)); > } > return null; > } > > protected Patch createNewPatch() { > byte[] b = new byte[20]; > for(int i=0; i<b.length; i++) { > b[i] = (byte) i; > } > Patch p = new Patch(new byte[20]); > editPatch(p); > return(p); > } I overrode editPatch() and I even overrode hasEditor(), but I still get no editor choice when I right-click on a new patch that I create. So... tell me what an idiot I'm being. - Joe |
From: Bill Z. <wrz...@po...> - 2005-03-08 04:53:51
|
Hmm .. my guess is JSL can't recognize the patch you made. A patch is expected to be a full sysex message by itself, and Driver.sysexID must be able to match it. (By default, it's an exact copy of the message your synth sent back as a dump.) So try copying the sysexID bytes to the beginning, and F7 at the end. As far as I know, JSL doesn't really associate a driver with a patch, even though it displays one in the list. If supportsPatch says nay, then you can't edit it. -Bill |
From: Joe E. <jo...@em...> - 2005-03-08 07:07:49
|
Bill Zwicky wrote: > Hmm .. my guess is JSL can't recognize the patch you made. A patch is > expected to be a full sysex message by itself ... even though the patch never appeared on any midi interface? Am I the only one who sees this as odd? > So try copying the sysexID bytes to the beginning, and F7 at the end. So... what happens if the world, someday, comes up with MIDI2 with some new sysex begin/end bytes instead of F0/F7? We go back and rewrite all of the drivers? - Joe |
From: Brian <br...@ov...> - 2005-03-08 14:53:24
|
> > So... what happens if the world, someday, comes up with MIDI2 with > some new sysex begin/end bytes instead of F0/F7? We go back and > rewrite all of the drivers? No. That would be unnecessary. Even if someday MIDI2 comes out, all existing synths will still be using MIDI1, so all existing drivers will work fine. At that time, we would merely have to code in MIDI2 support so that new drivers could be written for new synths. Existing drivers would not change. Please keep in mind that we've been developing JSynthLib for five years now. It may not always be clear why the code works the way it does, but It was put that way by someone intentionally to work around various issues that arose. In this case, the origional code did not insist on F0...F7, and we ran into problems with some synths that would send dumps like this: <JSynthLib sends Request Dump Message> Symth Sends Back: C0 0 0 FF FE F0 . . . .F7 FE FE C0 0 0, etc. If we treat the entire string as a patch and save it, when we try to load it back to the synth, the synth will not understand it. We have to extract the "Sysex" part of the midi stream from the rest of the stream. Many synths send active sensing messages constantly. Others will sporadically send controller messages in response to the slightest vibrations in the room. And of course, you always have the user accidently hitting a key on the synth during the dump. Extracting only system exclusive messages is important in getting clear and proper data from a synth. I'd be surprised if Sounddiver didn't do something similar. It's a feature, not a bug :) Brian |
From: Joe E. <jo...@em...> - 2005-03-09 00:15:38
Attachments:
smime.p7s
|
Brian wrote: >> >> So... what happens if the world, someday, comes up with MIDI2 with >> some new sysex begin/end bytes instead of F0/F7? We go back and >> rewrite all of the drivers? > > No. That would be unnecessary. Even if someday MIDI2 comes out, all > existing synths will still be using MIDI1, so all existing drivers > will work fine. Well, imagine if MOTU then came out with a MIDI2 version of their MidiExpress split/merge box.... and you've got all of your synths plugged into that. Suppose, also, that the box had a "feature" that reformatted all old-style sysex messages into newfangled (ie, using something other than F0/F7) new-style ones. Then, you'd have legacy JSL drivers receiving patches from legacy hardware... but with new-style messages coming into JSL. Granted... it's a *completely* contrived scenario... and it will probably *never* happen. But my point is this: sysex is a *transfer* protocol. It's a way of getting a data payload between two devices. Drivers should concern themselves with the payload, not with how it arrived.... because it causes unnecessary work for everybody and it makes it hard to adapt to future protocols. If it came in by midi (with F0/F7) or my carrier-pigeon or through morse-code on a telegraph, most drivers don't need to see the F0 and F7. For a real-world example, tell me how many of JSL's current synthdrivers set their "sysexID" variable to a string that does NOT begin with "F0"? I haven't stumbled across any yet. In fact, how many deviate from the "[F0][ManufacturerID][DeviceID][payload][F7]" format? Every device I currently own conforms to this message style. Yet, every JSL driver has to manually craft sysex messages itself. How many of the current drivers, do you estimate, all have an, essentially, identical bit of code in createNewPatch which takes the data of the patch and just slaps the F0 and the manuf and device ID's on the beginning and the F7 on the end? > ... we ran into problems with some synths that would send dumps like > this: > > <JSynthLib sends Request Dump Message> > > Symth Sends Back: > > C0 0 0 FF FE F0 . . . .F7 FE FE C0 0 0, etc. > > If we treat the entire string as a patch and save it, when we try to > load it back to the synth, the synth will not understand it. > We have to extract the "Sysex" part of the midi stream from the rest > of the stream. Right! JSL asked for a sysex message, and that's all that it grabs off of the wires. What I'm getting at is that, a vast majority of the time, JSL might as well lop the F0 and the F7 and give the driver the stuff inside. Well... getting back to my original problem, it turns out that the reason I couldn't edit the patch was exactly the reason most people suggested: the sysex message that I made in createNewPatch didn't match what I set sysexID to. Since I, personally, don't anticipate ever writing a driver that creates patches that it doesn't recognize (duh!), I don't see a reason why createNewPatch shouldn't use sysexID as the header of the sysex message in the patch. That way, it would be impossible to create a patch that didn't get an affirmative response from acceptsPatch() (or whatever that method is). What I ultimately did is made a subclass of Driver called LDDriver that just lets me set the manufacturerID and deviceID strings. Then, my *real* driver is a subclass of *that*, which only worries about the actual payload of the sysex message. When createNewPatch() is called in LDDriver, it gets the data payload from the subclass, an then slaps the F0, the manufID, and devID on the front and the F7 on the end. editPatch() will strip the same stuff *off* before passing it on to the subclass. So now... the actual driver subclass merely sets the manufID and devID in the constructor and then just worries about the data payload. Why am I telling you this? I'm not sure. I doubt anybody else is going to use it because it's not the established JSL way. I guess I'm just hoping that somebody else will see that doing it this way is A) simpler and less prone to mistakes, and B) applicable to probably 75% or more of the devices we'll come across (and the remaining 25% are still free to use subclass Driver directly). Anyway... the nice doctors with their scalpels are at the door now, so I'll stop complaining and conform now.. - Joe |
From: Brian <br...@ov...> - 2005-03-09 16:25:50
|
> > For a real-world example, tell me how many of JSL's current > synthdrivers set their "sysexID" variable to a string that does NOT > begin with "F0"? I haven't stumbled across any yet. In fact, how many > deviate from the "[F0][ManufacturerID][DeviceID][payload][F7]" format? > Every device I currently own conforms to this message style. Yet, > every JSL driver has to manually craft sysex messages itself. How many > of the current drivers, do you estimate, all have an, essentially, > identical bit of code in createNewPatch which takes the data of the > patch and just slaps the F0 and the manuf and device ID's on the > beginning and the F7 on the end? Alot do, actually a lot of synths have pretty complex "Default Patches", so the drivers actually store a dump of a "Default Patch" in a file and load it in when create new patch is performed. > > Right! JSL asked for a sysex message, and that's all that it grabs off > of the wires. What I'm getting at is that, a vast majority of the > time, JSL might as well lop the F0 and the F7 and give the driver the > stuff inside. I dunno. Some synths have a patch dump made up of multiple F0..F7 pairs. For example, the Boss DR-660 Driver, a patch is actually i think 14 sysex messages sent in quick succession. Lopping off the first and last byte but leaving the others in place would be kind of odd and it would be a nightmare to have to insert a bunch of F0 and F7's all throughout the patch in order to send or receive data. Especially since not all the sub-messages have a fixed size. > Why am I telling you this? I'm not sure. I doubt anybody else is going > to use it because it's not the established JSL way. I guess I'm just > hoping that somebody else will see that doing it this way is A) > simpler and less prone to mistakes, and B) applicable to probably 75% > or more of the devices we'll come across (and the remaining 25% are > still free to use subclass Driver directly). I appreciate what you are trying to do, but belive me, you are making things much harder on yourself by doing this. This kind of thing always seems like it would be simpler, but it ends up causing problems. There are many different interfaces and API's JSynthLib has to support for patches. In every case, whenever I tried to design something clever to make driver writing easier, it ended up making things more complicated because some synth manufacturer did some attrocious thing with their sysex spec. I think It's easier to tell a driver writer, whatever bizzare data your manufacture prepends to the patch, insert that here... and have it always work, then have to explain put your manufactuer ID here, your device ID here, this is the standard sysex representation of that data, if your synth doesn't use that than subclass this instead.... True it would make it a tiny bit easier in 75% of the cases, but it would make things a nightmare for the other 25%. Please understand that we have an "established JSL way" not because we want to be subborn or because we want to make your life more difficult but because our way works for all supported synths. Collectively, we have written driviers for over fify synthesizer models. The interfaces and paradigms evolve over time as one after another any pleasing abstraction we use gets smashed by some amazingly atrocious sysex spec which goes ahead and does something completely incompatable with our assumptions and abstractions. In truth, I fear any abstraction at a higher level than "A patch is an array of bytes." Is going to be violated by some as of yet unsupported synth. Plus I would hate to write an editor where I had to worry that what the manual was calling byte number 55, was actually byte number 48 in the array I was passed because some stuff had been stripped off the front. That said, it is a good idea to look back occasionally at what has evolved and look to see if it can be refactored without losing anything. We've been doing this for quite some time. If you think the current source is driving you insane, go find a copy of version 0.16. Helper classes which make the common case easier to implement are a *good thing* as long they are easy and intuitive to work around in the (unfortunately all to common) case where a synth spec refuses to cooperate. One example of this, is that we provide a default "Compute Checksum" method so that many synths don't have to implement it themselves, but if (again all to commonly) the synth uses some other approach to checksum computation or even uses multiple checksums (again way too common), the author can override this. I don't think that having to subclass a different version of driver just to work around some simple thing is viable. Brian |
From: Joe E. <jo...@em...> - 2005-03-10 02:14:22
Attachments:
smime.p7s
|
Brian wrote: >> >> For a real-world example, tell me how many of JSL's current >> synthdrivers set their "sysexID" variable to a string that does NOT >> begin with "F0"? I haven't stumbled across any yet. In fact, how many >> deviate from the "[F0][ManufacturerID][DeviceID][payload][F7]" >> format? Every device I currently own conforms to this message style. >> Yet, every JSL driver has to manually craft sysex messages itself. >> How many of the current drivers, do you estimate, all have an, >> essentially, identical bit of code in createNewPatch which takes the >> data of the patch and just slaps the F0 and the manuf and device ID's >> on the beginning and the F7 on the end? > > > > Alot do, actually a lot of synths have pretty complex "Default > Patches", so the drivers actually store a dump of a "Default Patch" in > a file and load it in when create new patch is performed. > >> >> Right! JSL asked for a sysex message, and that's all that it grabs >> off of the wires. What I'm getting at is that, a vast majority of the >> time, JSL might as well lop the F0 and the F7 and give the driver the >> stuff inside. > > I dunno. Some synths have a patch dump made up of multiple F0..F7 > pairs. For example, the Boss DR-660 Driver, a patch is actually i > think 14 sysex messages sent in quick succession. Lopping off the > first and last byte but leaving the others in place would be kind of > odd and it would be a nightmare to have to insert a bunch of F0 and > F7's all throughout the patch in order to send or receive data. > Especially since not all the sub-messages have a fixed size. Two things: 1 - If the driver receives multiple F0...F7 pairs, then you could lop the F0's and F7's off of all of them and the driver could just get an array of sysex payloads. I dunno. The more we discuss stripping the F0/F7, the more I think "This is silly to raise such a fuss over just two bytes". The two arguments I have in support of raising a fuss. First, I suspect that a majority of the drivers all have code to strip/disregard those bytes on incoming messages and to replace them on outgoing ones. Each time someone does it, it raises the possibility of a bug and it contributes to code-bloat. The second argument is that, the first time I ever looked at an existing driver (as the programming.html suggested), the first thing I saw at the top of the file was a fully-formed sysex ID string. The thought that went through my mind "Wait a minute... I thought the whole point of the design was to *insulate* me from the minutae of sysex and allow me to just deal with the data *within* the sysex messages.". As a programmer, it caused me to have doubts about the wisdom of the design of the program... which made me reluctant to invest much effort in learning how to code for it. In short, I think looking at current driver implmentations could be scaring some potential developers away. 2 - I'm not saying that we have to make every driver use some new design. That's what sublcassing is for. Imagine having Driver, with its complicated way of doing things. You could make a subclass of that called, say, MoreConformingDriver, which is designed for patch dumps with a single sysex message which have [F0][data][F7] format and the programmer just deals with that [data]. Then, you could have a subclass of *that* called EvenMoreConformingDriver, which is just like its superclass, but deals with patch dumps of the format [F0][ManufacturerID][DeviceID][data][F7] and, again, the programmer just deals with the [data] part and everything else is handled transparently. Now, from what you tell me, it sounds like the Boss DR-660 wouldn't be able to make use of EvenMoreConformingDriver. Fine. It would continue to subclass Driver. However, I think that it would save a lot of coding (and look more inviting to potential new developers) if driver constructors contained a few simple commands like I'm doing with the driver I'm working on: setManufacturerID("00000E"); setDeviceID("05"); setDecodingType(ALESIS); Just those three commands, and then my createNewPatch and editPatch methods get to just deal with the (decoded to 8-bit) bytes after the DeviceID and before the F7. Heck, someone could make a subclass of *that* called "EvenMoreConformingAlesisDriver" and then all you'd need to do is set your deviceID! Maybe it's just me... but I feel that, if you're writing for a device that is fairly standard, then subclasses like this could save a lot of time, because you only deal with the level of complexity that you need to. > I think It's easier to tell a driver writer, whatever bizzare data > your manufacture prepends to the patch, insert that here... and have > it always work, then have to explain put your manufactuer ID here, > your device ID here, this is the standard sysex representation of that > data, if your synth doesn't use that than subclass this instead One thing that I find disconcerting, however, is the fact that it's not easy to know what data elements you have to set. For example, while writing my driver, I tried to "Get" a patch... and I got an exception thrown. After I hunted around, I figured out that it was because I hadn't initialized "String[] patchNames". Well... how silly of me! *Everybody* knows that you have to initialize patchNames. :P So, I think that it would make driver development a little smoother if it were easier to know what info you needed to provide for things to work. One idea would be to have EvenMoreConformingDriver an abstract class and to make some abstract methods for getDeviceID and getManufacturerID. Then, if you try to subclass it, you'll get compile errors if you don't implement them. This is good for two reasons: First, compile-time errors are generally better than runtime-errors since the *user* can't encounter a compile-time error, and secondly, because it would be easier for the developer to tell, from the error, what the problem was. Of course, using abstract classes is just one possiblity. Maybe it could be done with interfaces... I dunno. But you get the idea. > Plus I would hate to write an editor where I had to worry that what > the manual was calling byte number 55, was actually byte number 48 in > the array I was passed because some stuff had been stripped off the front. I've got the opposite problem, where my spec calls the byte after the deviceID "byte 0". So, nyeah! :) > That said, it is a good idea to look back occasionally at what has > evolved and look to see if it can be refactored without losing anything. And keep in mind that I'm willing to put in a lot of effort to aid any refactoring. I'm not the kind to say "This all sucks... you guys fix it and call me when you're done.". If it is decided to make a change, I'll be the first one diving in to help convert old stuff so that it works with the new stuff, if need be. > One example of this, is that we provide a default "Compute Checksum" > method so that many synths don't have to implement it themselves, but > if (again all to commonly) the synth uses some other approach to > checksum computation or even uses multiple checksums (again way too > common), the author can override this. Do you know of any technical barrier to putting all of the various checksum algorithms into one class, so that something like the hypothetical EvenMoreConformingDriver could use something like: setChecksumType(YAMAHA_PRE_1996); in the constructor? I didn't say *psychological* barriers.... I said *technical*. :) - Joe |
From: Brian <br...@ov...> - 2005-03-10 14:50:08
|
> > Do you know of any technical barrier to putting all of the various > checksum algorithms into one class, so that something like the > hypothetical EvenMoreConformingDriver could use something like: > setChecksumType(YAMAHA_PRE_1996); > in the constructor? I didn't say *psychological* barriers.... I said > *technical*. :) No. I think that would be a good idea if someone is willing to put in the time. The only barrier is how to get people to know which checksum to use. But if you know the different checksum types in use and how to name them such that people will know which one to pick, please do. The major problem I've had so far is that most manuals don't say "We use the foo algorithm" for checksumming, they usually just give the step by step algorithm. From a driver writers pov, I've found it easier just to take this algorithm from the manual and type it in for each driver, than to check all the other drivers already written and try to figure which one is doing the same thing. If the checksum algorithms can really be boiled down to things like YAMAHA_PRE_1996, than that would be great. Please note also that there is ongoing work to allow future drivers to be written as XML files which describe the device rather than having to write everything in java. If we are going to add some niceties to the driver writing process it might be worthwhile to see how the niceties could be carried over such that they are available to XML drivers as well. Brian |
From: Joe E. <jo...@em...> - 2005-03-10 22:21:13
Attachments:
smime.p7s
|
Brian wrote: >> >> Do you know of any technical barrier to putting all of the various >> checksum algorithms into one class, so that something like the >> hypothetical EvenMoreConformingDriver could use something like: >> setChecksumType(YAMAHA_PRE_1996); >> in the constructor? I didn't say *psychological* barriers.... I said >> *technical*. :) > > No. I think that would be a good idea if someone is willing to put in > the time. The only barrier is how to get people to know which checksum > to use. Well, there'd have to be some copious comments with each method in the class explaining exactly what each one does. Actually, I was contemplating the same kind of thing for devices that need to do some kind of 7-bit-to-8-bit conversion, like with Alesis stuff. Take a look at Zellyn's AlesisQS SysexRoutines.java and you can see the kind of explicit commenting I'm thinking of: http://cvs.sourceforge.net/viewcvs.py/jsynthlib/JSynthLib/synthdrivers/AlesisQS/SysexRoutines.java?view=markup Additionally... has there been any talk about having a Wiki for describing how drivers interact with JSL? > But if you know the different checksum types in use and how to name > them such that people will know which one to pick, please do. The > major problem I've had so far is that most manuals don't say "We use > the foo algorithm" for checksumming, they usually just give the step > by step algorithm. From a driver writers pov, I've found it easier > just to take this algorithm from the manual and type it in for each > driver, than to check all the other drivers already written and try to > figure which one is doing the same thing. If the checksum algorithms > can really be boiled down to things like YAMAHA_PRE_1996, than that > would be great. Well, you've seen more checksum algorithms than I have, so you're a better judge of whether they tend to remain the same on a per-manufacturer basis. I'm *hoping* that there's some sense of sanity to the grouping... such that we could put in the comments (or a Wiki): /** * GENERIC - This is the most common checksum type. It adds up blah blah blah and appends it to location XYZ. * NONE - This calculates no checksum and doesn't add any bytes to the message * BOSS_DR - Most Boss and Roland drum machines use this one. It calculcates it like... blah blah blah. */ Along with that, should be a section listing manufacturers, so that a new developer doesn't have to read the explanation of each checksum type: /** * Alesis - Most use GENERIC. A few of their XJUE-series synths use the YAMAHA_PRE_1996 style * Boss - Most use NONE, but their drum machines use BOSS_DR *... Even if this info isn't completely thorough, it should be easy enough for a developer to just *try* a few likely candidates. In fact.... I think that it's entirely possible to write a method which, given a known-good (ie, received as a patch dump) patch, tests it against all current checksum methods and reports back which methods the patch works with. > Please note also that there is ongoing work to allow future drivers to > be written as XML files which describe the device rather than having > to write everything in java. I know. I've been having a good conversation with Rib Rdb about better-integrating the XML driver into devicesConfig. > If we are going to add some niceties to the driver writing process it > might be worthwhile to see how the niceties could be carried over such > that they are available to XML drivers as well. Actually, in order to do this, it would also make it really easy to make a "tellMeWhatChecksumsWorkWithThisPatch" method. So, we'd kill two birds with one stone. - Joe |
From: Bill Z. <wrz...@po...> - 2005-03-11 02:40:13
|
Joe Emenaker wrote: > /** > * GENERIC - This is the most common checksum type. It adds up blah > blah blah and appends it to location XYZ. > * NONE - This calculates no checksum and doesn't add any bytes to > the message > * BOSS_DR - Most Boss and Roland drum machines use this one. It > calculcates it like... blah blah blah. > */ I got a better idea: Since we're using an object-oriented language, why not use objects? synthdrivers.Generic.Checksum synthdrivers.Boss.DRChecksum synthdrivers.Casio.CZ1000.Driver implements Checksum This way if a new checksum is developed, noone needs to go edit the existing code base, nor twiddle the double-indirection constants, nor edit documentation in multiple places (source, Wiki). -Bill |
From: Joe E. <jo...@em...> - 2005-03-11 20:32:30
Attachments:
smime.p7s
|
Bill Zwicky wrote: > I got a better idea: Since we're using an object-oriented language, > why not use objects? > > synthdrivers.Generic.Checksum > synthdrivers.Boss.DRChecksum > synthdrivers.Casio.CZ1000.Driver implements Checksum > > This way if a new checksum is developed, noone needs to go edit the > existing code base, nor twiddle the double-indirection constants, nor > edit documentation in multiple places (source, Wiki). Well.... a few reasons why that could be bad are: 1 - There's probably a lot of redundancy/commonality in checksum algorithms, and that redundancy doesn't follow any lines of inheirtance of the classes. In other words, it would probably be pretty rare that a synthdriver would get the apropriate checksum method from its superclass (if at all). Without benefitting from inheritance, each synthdriver still has to define their checksum method, which means that you'd get a lot of stuff like this: public Checksum generateChecksum(Patch p) { return synthdrivers.Casio.CZ1000.Driver.generateChecksum(p); } 2 - Not only is the above code unsightly, it also causes synthdrivers to stick their fingers into other synthdrivers' business. This is bad for two reasons. First, (and this might just be personal preference) I've found that it's poor design to have low-level parts of the software try to have any sort of awareness of other parts. A synthdriver should have absolutely no clue (and, ideally, no way of finding out) if it's the only driver loaded, or one of 100. Usually, this ideal is merely good for helping to promote good OO design, which isn't a life-or-death situation. However, the *second* reason makes it a little more crucial. The second reason is that I'm still holding out hopes that, someday, JSL will allow the user to dynamically browse/retrieve/update their drivers over the net. If this ever becomes reality, then we can't be certain *which* synthdrivers are currently installed on the user's machine and which aren't. Unless we want to come up with some kooky requirement system (ie, "Korg ER-1" requries "CasioCZ1000"), then this could be a deal-killer for any future net-based driver download system. 3 - This solution would make it harder on the XML driver. I'd personally like to see <Checksum type="YAMAHA_PRE_1996" /> instead of <Checksum class="synthdrivers.Yamaha.EX5.BankDriver" /> - Joe |
From: Hiroo H. <hir...@co...> - 2005-03-12 23:34:47
|
Hi, Well, there were so many mails on this ML this week. It's good news for this project. But it's very difficult for me to read them... Let me reply on this check sum issue first. (Sorry, this mail gets long, too.) There were discussions about this issue since I joined this ML. The current implementation is the best way I could think of. 1. The interfaces between core and synthdrivers expect a patch whose check sum is already calculated, and do not have method to calculate check sum. 2. core interfaces a patch by using IPatch interface. 3. The current synthdrivers extend Driver class which is called via IPatch interface. 4. Driver class has the following *protected* classes. /** * Calculate check sum of a <code>Patch</code>.<p> * * Need to be overridden if a patch is consist from multiple SysEX * messages. * * @param p a <code>Patch</code> value */ protected void calculateChecksum(Patch p) { calculateChecksum(p, checksumStart, checksumEnd, checksumOffset); } The original Driver class had the method above. /** * Calculate check sum of a <code>Patch</code>. * <p> * * This method is called by calculateChecksum(Patch). The checksum * calculation method of this method is used by Roland, YAMAHA, etc. * Override this for different checksum calculation method. =2E.. */ protected void calculateChecksum(Patch patch, int start, int end, int offset) { DriverUtil.calculateChecksum(patch.sysex, start, end, offset); } The method above was introduced to make being reused easier. DriverUtils class has the following *static* method. By using *static* method we can call it without inheriting nor creating object. (For example a bank driver can share check sum method with a single driver easily). /** * Calculate check sum of a byte array <code>sysex</code>. * <p> * * The checksum calculation method of this method is used by Roland, YA= MAHA, * etc.<p> * =2E.. * @see Driver#calculateChecksum(Patch) */ public static void calculateChecksum(byte[] sysex, int start, int end, = int ofs) { int sum =3D 0; for (int i =3D start; i <=3D end; i++) sum +=3D sysex[i]; sysex[ofs] =3D (byte) (-sum & 0x7f); } What we can do is to add variation of this method on this class and let programmers choose one of them. The most difficult work is to name them as someone pointed. It is not difficult for programmers to implement this level of code. And it may be more difficult for them to select one of methods provided:-)=20 And my manual for Roland synth explain check sum as follows; aa + bb + cc + ... + hh =3D sum sum / 128 =3D quotient ... remainder 128 - remainder =3D check sum It might be even more difficult to understand the method above implements this calculation method. Better documentation may help some, but I have little hope. --=20 Hiroo Hayashi |
From: Joe E. <jo...@em...> - 2005-03-14 06:42:40
|
Bill Zwicky wrote: > And the only *good* solution to that is for each driver to have its > own private copy of checksum(). We really *don't* want changes in the > common code to break drivers; each driver should have its own code. I think that we'd have more bug-free checksum methods if they were centralized in core.*. If there's a bug in one of the checksum methods that was being used by multiple synthdrivers, it would get noticed and fixed sooner. The problem with changes in core breaking synthdrivers isn't a big problem because we have CVS. If someone breaks one of the checksum methods, we can easily fix it back. Hiroo Hayashi wrote: >And my manual for Roland synth explain check sum as follows; > > aa + bb + cc + ... + hh = sum > sum / 128 = quotient ... remainder > 128 - remainder = check sum > >It might be even more difficult to understand the method above >implements this calculation method. > I consider it to be understood that there would need to be *plentiful* comments in a checksum class, perhaps going as far as to quote the checksum method from various manuals, like Hiroo has. In other words, we could write "If your sysex specification describes the checksum method as: 'aa + bb +... 128 - remainder = check sum', then use the following method" directly in the javadoc comment for the method. - Joe |
From: Joe E. <jo...@em...> - 2005-03-15 06:18:53
|
Bill Zwicky wrote: > Joe Emenaker wrote: > >> I think that we'd have more bug-free checksum methods if they were >> centralized in core.*. If there's a bug in one of the checksum >> methods that was being used by multiple synthdrivers, it would get >> noticed and fixed sooner. > > How many buggy checksummers do we have now? I don't know because: A) some checksum methods might have bugs that only show up 1 in 128 or 1 in 16384 times. B) the author of the synthdriver might have just copied a buggy one from another synthdriver and just coded around it. I'm assuming that your point is: "It's not that difficult to write a checksum method", and you're right. However, if enough of them are written from scratch, buggy ones *will* happen. Time will cause the improbable to be inevitable. > What are the odds that fixing a "bug" in a common checksummer will > actually break some other synth? The only way, that I can see, that would cause it to break another synthdriver is if that synthdriver *accounted* for the bug with its own code. But two wrongs don't make a right. I bug in a checksum method is a mistake. Trying to solve the problem by tweaking *other* parts of the synthdriver (instead of the checksum method) is *also* a mistake. > Does anyone actually *have* the problem you're solving? Well, I think the XML driver will. It's going to need (or want) to be able to choose checksum methods with a text string. More importantly, the problem I'm trying to solve is one of long-term code maintenance. Right now, there could be dozens of copies of someone's original checksum algorithm. What if a seldom-occuring bug is found in the original? I doubt that anybody is going to go find all of the other synthdrivers that copied its method. (My apologies to non-native English speakers at this point, because I should probably stop here, but I want to add a couple more points). I'm also trying to solve future code-bloat. I'm looking forward to the day when JSL has support for 1,000+ devices. Even if we are lucky and *every* developer in the entire future of JSL writes flawless checksum methods, then our best possible outcome is needlessly-bloated code and a lot of duplicated effort. Lastly, having centralized checksum methods doesn't *prohibit* having specialized ones, anyway. We could put the 4 or 5 most-common ones in core.* and still allow individual synthdrivers to put in their own. - Joe |
From: Rib R. <ri...@gm...> - 2005-03-15 08:17:59
|
On Mon, 14 Mar 2005 22:18:11 -0800, Joe Emenaker <jo...@em...> wrote: > Bill Zwicky wrote: > > Does anyone actually *have* the problem you're solving? > > Well, I think the XML driver will. It's going to need (or want) to be > able to choose checksum methods with a text string. The XML driver is able to choose checksum methods with a string. It uses PluginRegistry to locate plugins (which currently must be written in Groovy) inside the org.jsynthlib.plugins package and also in user specified directories. I suppose it would be possible to require these plugins to work with Patch, but I don't really see the point. My personal opinion is that we leave current drivers as they are, and work to make the XML driver provide a cleaner interface for new drivers. Working towards this goal, I've converted EditorBuilder to be able to read parameters from an XML driver and to export XML instead of Java code. I've almost finished the parser. Once it (the parser) is done the XML driver should be ready for simple single editors. Then we need to start using it so we can improve it. (For example, I think Decoders need to be extended to allow for cases where multiple parameters are decoded at once.) |
From: Joe E. <jo...@em...> - 2005-03-15 08:44:33
|
Rib Rdb wrote: >The XML driver is able to choose checksum methods with a string. > You're no help. :) >My personal opinion is that >we leave current drivers as they are, and work to make the XML driver >provide a cleaner interface for new drivers. > > I'm not necessarily saying that we need to change the old drivers. I'm saying that we ought to put common checksum methods in a central class so that future non-XML drivers can use it. I felt that this would also benefit the XML driver, since authors could write something like <Checksum type="ROLAND_COMMON" /> - Joe |
From: Brian <br...@ov...> - 2005-03-15 14:58:36
|
> > Lastly, having centralized checksum methods doesn't *prohibit* having > specialized ones, anyway. We could put the 4 or 5 most-common ones in > core.* and still allow individual synthdrivers to put in their own. Since we've already made the decision long ago to put the normal case checksum in core anyway, I don't see why we couldn't have a few in core. Its not a question of all in core or none in core, its a question of is the checksum algorithm in core so much more general than the others that it deserves special treatment, or are there a small class of algorithms that should all be considered equally generic and go in core. If there are several synthdrivers using the same algorithm, I see no reason not to refactor and place that algorithm in core. However we must be very careful not to break any drivers in doing this. |
From: Bill Z. <wrz...@po...> - 2005-03-17 02:55:51
|
Joe Emenaker wrote: > The only way, that I can see, that would cause it to break another > synthdriver is if that synthdriver *accounted* for the bug with its > own code. But two wrongs don't make a right. I bug in a checksum > method is a mistake. Trying to solve the problem by tweaking *other* > parts of the synthdriver (instead of the checksum method) is *also* a > mistake. > No no, you have it backwards: What if the synths themselves are buggy? What if someone tweaks the common driver to work around bugs in their synth, but that triggers bugs in someone else's synth? Bah, there's no arguable point here. The problem is one of maintaining 50+ synth drivers and more. I'm inclined to think that the drivers should be kept seperate so that hacking on one driver doesn't break the other 49. But if there's common code, it should be pulled out to a common place. > Well, I think the XML driver will. It's going to need (or want) to be > able to choose checksum methods with a text string. > True, but the XML driver is a completely seperate problem.. > More importantly, the problem I'm trying to solve is one of long-term > code maintenance. > I'm also trying to solve future code-bloat. I'm looking forward to the > day when JSL has support for 1,000+ devices. Those are seperate problems too. We're using Java on Gigahertz class machines; bloat is not a problem. Trust me on this, bloat is *really* not a problem. Even with 1000 synth drivers, the overhead of Java will completely dwarf this little project. Now maintainence *is* a problem, and bloat that makes maintenance difficult is *definitely* a problem. Specifically: > Even if we are lucky and *every* developer in the entire future of JSL > writes flawless checksum methods, then our best possible outcome is > needlessly-bloated code and a lot of duplicated effort. 1000 duplicate checksummers is *not* a problem as far as code size is concerned. But what about maintenance? Well, how do you modify code that affects multiple synths that you don't own? How do you maintain this code without having all 1000 synths around you? This is why I keep pushing for isolated code. I think it's important that hacking on a driver not affect any other driver. I also think common code should be placed in a common location, but in this case, we should only do that when someone can tell us *definitively* that two synths are identical. -Bill |
From: Joe E. <jo...@em...> - 2005-03-17 09:10:53
|
Bill Zwicky wrote: > Joe Emenaker wrote: > >> The only way, that I can see, that would cause it to break another >> synthdriver is if that synthdriver *accounted* for the bug with its >> own code. But two wrongs don't make a right. I bug in a checksum >> method is a mistake. Trying to solve the problem by tweaking *other* >> parts of the synthdriver (instead of the checksum method) is *also* a >> mistake. > > No no, you have it backwards: What if the synths themselves are > buggy? What if someone tweaks the common driver to work around bugs > in their synth, but that triggers bugs in someone else's synth? Well, you make the rule that nobody is allowed to "tweak" any of the common checksum methods. You can "fix" bugs that you discover, but you don't go in and just add some stuff that gives you the results you need without identifying a flaw in the existing code. In other words, if you're using a common checksum method and you're getting a bad checksum, either: 1 - There's a bug in your synthdriver 2 - You're using the wrong checksum method, or 3 - There's a bug in the checksum method itself. In those cases, respectively, you: 1 - Fix your synthdriver 2 - Figure out the correct checksum method to use, or 3 - Notify the list that you think the checksum method is broken. Do *not* tweak your driver to get around the bug because, if the bug is ever fixed, it could break your driver. > But if there's common code, it should be pulled out to a common place. Of course. I thought that was a given. For example, we could use... org.jsynthlib.util.CommonChecksums >> Well, I think the XML driver will. It's going to need (or want) to be >> able to choose checksum methods with a text string. > > True, but the XML driver is a completely seperate problem. Well, I think that the XML driver shouldn't have to be a special case. I think the XML driver should, from the perspective of the higher JSL code, act just like all of the others. I've already tossed around some ideas with Rib Rdb off-list for cleaning the XML-specific stuff out of devicesConfig. But that's probably a separate discussion. >> I'm also trying to solve future code-bloat. I'm looking forward to >> the day when JSL has support for 1,000+ devices. > > Those are seperate problems too. We're using Java on Gigahertz class > machines; bloat is not a problem. Trust me on this, bloat is *really* > not a problem. We have only about 100 synthdrivers and it takes me close to 1 minute to do a CVS update. >> Even if we are lucky and *every* developer in the entire future of >> JSL writes flawless checksum methods, then our best possible outcome >> is needlessly-bloated code and a lot of duplicated effort. > > 1000 duplicate checksummers is *not* a problem as far as code size is > concerned. But what about maintenance? Well, how do you modify code > that affects multiple synths that you don't own? How do you maintain > this code without having all 1000 synths around you? > > This is why I keep pushing for isolated code. I think it's important > that hacking on a driver not affect any other driver. Well, I don't think anybody should be "hacking" on anything in JSL. If something doesn't work, you don't work around it. You find the problem and fix it. If other people encountered the problem earlier and just worked around it, I'd say that they made a mistake... and that that should be fixed, too. But I don't think that this will be as much of a problem as you fear. First, checksum routines are pretty easy to get correct, and any errors that are made would be fairly likely to be discovered quickly (even quicker when mulitple drivers use that checksum method). Secondly, I'm not necessarily saying that we need to go back to all of the old drivers and change them so that they use common checksum methods. I'm thinking more of future drivers. - Joe |
From: Bill Z. <wrz...@po...> - 2005-03-19 20:33:16
|
Joe Emenaker wrote: > We have only about 100 synthdrivers and it takes me close to 1 minute > to do a CVS update. Do like I do: Start the update, then go read e-mail. This really isn't a problem we should worry about. -Bill |
From: Hiroo H. <hir...@co...> - 2005-03-08 05:13:38
|
Joe> So... tell me what an idiot I'm being. If you were idiot, it might be because you did not give us the real code which you used:-) 1. Your code cannot be compiled. 2. Even if you fix the syntax errors, JSynthLib cannot find your driver. P.S. I played Roundabout, Heart of the Sun Rise, and some more in my high school band. Lonely Heart was not released yet. A long long time ago... I'm glad to feel that I become closer to one of the great band members. -- Hiroo Hayashi |
From: Joe E. <jo...@em...> - 2005-03-08 06:50:12
|
Hiroo Hayashi wrote: >Joe> So... tell me what an idiot I'm being. > >If you were idiot, it might be because you did not give us the real code >which you used:-) > >1. Your code cannot be compiled. > > Sorry. I left the beginning junk (like the import statements, package statement, etc.) and an ending curly bracket. I figured people would be able to look at the code segment and tell what I was doing wrong. >2. Even if you fix the syntax errors, JSynthLib cannot find your driver. > > Well, it seems to *find* it okay because my device and driver show up in the "New Patch..." dialog. I can create a new patch... it just doesn't edit it. - Joe |