Yamaha SU700
I bought a Yamaha SU700. It's a sample-based groovebox released by Yamaha in 1998. 44.1KHz 16-bit stereo sampling, 43 effects, between 4 and 48MB of memory, and optional expansion cards in addition to to the Floppy drive. A real beast of its time, and arguably just a Yamaha A3000 you can take on the road.
Details
There's a lot of buttons and knobs and pads on this thing. We'll get to the knobs later, but the pads are (for those responsible for playing samples) velocity-sensitive, and broken into three groups:
- "Loop", which plays its assigned samples continuously.
- "Composed Loop", which plays its assigned sample at the same place(s) each bar.
- "Free", which plays its assigned sample on the specific beat and bar it was pressed.
These groups are kind of arbitrary. On one hand, they do quicken making music, as you can slap your drums and bass/synth on the loop pads, a couple of pads on the composed loop pads, and you have something going pretty much instantly. On the other, you can achieve the same thing with the free pads by pressing them at the right time - so it would clearly be better to just have 8 free pads.
There's a slew of buttons in the middle which perform miscellaneous tasks like loading samples, saving projects, and erasing 'events' on tracks (as if you'd never pressed them. I'm still not clear what the scene and marker buttons do. I suppose I need to read the manual. It's plenty fun even without reading it.
The touch-bar-esque device on the right is a "ribbon" that allows you to modulate the value of the left-hand buttons in a way that's more convenient than turning a knob. Though I've mostly only used it to play with cutoff for that 'opening-up' sound.
Finally, the buttons on the left relate to tracks/pads. You press the button, and then use the colourful knobs to tweak the value. Which leads to the first issue:
Rotary Encoders
Yamaha seem real bad at making/picking rotary encoders. The A3000 was shite in that respect too. Fortunately, they can be replaced with some work. I opted to go for the ALPS EC12E2420802, which worked out around 1.30GBP each. However, annoyingly, the encoders used by Yamaha have four legs instead of three, and the arrangement of the legs differs. Which means jumpers are required. I managed to get buy with some 22AWG solid-core I had kicking about. But if I were doing it again, I'd maybe opt for something thinner and use longer bits of wire.
Adding Samples
This is the biggest disadvantage to the SU700. By far. In it's "stock" configuration, you have a floppy drive, and that's it. Unsurprisingly, 1.44Mb doesn't get you very far. The workflow in this configuration is as follows:
- On a computer, export your samples as AIFF.
- Copy those samples onto a floppy formatted as FAT12.
- Insert the floppy and use the "LOAD" button combo to assign it to a track.
- Eject the floppy and insert the next one, because you didn't get all of it on one disk.
This works, and is how Yamaha intended you to do it. But we can do one better. Rather than piss-about with actual floppy disks (admitedly, they do have an aesthetic about them that makes me like the idea of having a shelf full of curated samples) - we emulate a floppy disk drive.
GOTEK make floppy-drive emulators. You replace your actual floppy drive with one, and then put your floppy images onto a FAT32/exFAT USB stick. You can then use the front-panel of the GOTEK to select the currently 'inserted' floppy.
This then leads to a question of how you 'get' floppy images. In my case, I used the SU700 to format a real floppy, then used dd to dump it to a file named "BLANK.IMG". I could then mount that file in BSD/Linux/MacOS, copy my samples, and eject it. All good. But tedious. Thus:
autofloppy.rb
#!/usr/bin/env ruby # Crawl directories and group samples into 1.44Mb directories, # which are then copied into floppy images. require 'pry' require 'fileutils' # Samples should be stored in the following structure: # root/samples/{type}/{collection}/sample_a.aiff # i.e. root/samples/vocal/junglehitsvol1/sample_a.aiff # sample_b.aiff # sample_c.aiff # This will yield a structure like so: # root/floppies/{type}/{collection}/{type}{collection}{n}.img # i.e. root/floppies/drumloops/jungle_samples/DLJUN001.IMG # Valid types (defined in SampleLibrary) # drumloop # syntloop # stab # pad # fx # vocal # SampleLibrary contains SampleBanks (drumloops, stabs, etc) # SampleBanks contain SampleCollections (drumloops from AKAI Sampler CD #120, #69, etc) # SampleCollections contain SampleBatches (samples grouped into 1.44MB blocks) class SampleLibrary def initialize(root) @root = root @floppy_dir = root + "/floppies" @blank_floppy = root + "/floppies/BLANK.IMG" @blank_floppy_name = "SU700 DISK" @samples_dir = root + "/samples" @sample_types = {"drumloops" => "DL", "bassloops" => "BL", "synthloops" => "SL", "stabs" => "ST", "pads" => "PD", "fx" => "FX", "vocal" => "VO" } @banks = {} @sample_types.each do |sample_type, shortcode| sample_type_dir = @samples_dir + "/" + sample_type next unless Dir.exist?(sample_type_dir) @banks[sample_type] = SampleBank.new(sample_type_dir, sample_type) end @banks.each do |sample_type, bank| unless Dir.exist?(@floppy_dir) then Dir.mkdir(@floppy_dir) end st_dir = "#{@floppy_dir}/#{sample_type}" unless Dir.exist?(st_dir) then Dir.mkdir(st_dir) end bank.collections.each do |col| col_dir = "#{@floppy_dir}/#{sample_type}/#{col.name}" unless Dir.exist?(col_dir) then Dir.mkdir(col_dir) end col.batches.each_with_index do |batch, idx| floppy_path, floppy_name = long_to_short(sample_type, @sample_types[sample_type], col.name, idx) puts "Creating floppy #{floppy_path}" FileUtils.copy(@blank_floppy, floppy_path) block_path = "/dev/loop16" mount_path = "/mnt/fd" %x{losetup #{block_path} "#{floppy_path}"} %x{mount -t msdos #{block_path} #{mount_path}} puts "Mounted floppy #{floppy_name} at #{mount_path} (#{block_path})-- copying." batch.files.each do |file| file_size = File.size(file) new_file_name = file.split("/")[-1].upcase.tr(" ", "").sub(".AIF", "")[0..8].strip + ".AIF" puts "Copying #{file} to #{mount_path}/#{new_file_name} (#{file_size} bytes)" FileUtils.copy(file, "#{mount_path}/#{new_file_name}") %x{rm -rf "#{mount_path}/fseven*"} end puts "Renaming #{@blank_floppy_name} to #{floppy_name}" %x{fatlabel "#{block_path}" "#{floppy_name}"} puts "Syncing...." %x{sync} puts "Dismounting #{mount_path} (#{block_path})" %x{umount "#{mount_path}"} %x{losetup -D} end end end end def long_to_short(st_l, st_s, collection, num) colname = collection[0..2].upcase padnum = num.to_s.rjust(3, '0') short_name = "#{st_s}#{colname}#{padnum}" return "#{@floppy_dir}/#{st_l}/#{collection}/#{short_name}.IMG", short_name end end class SampleBank attr_reader :path, :sample_type, :collections def initialize(bank_dir, stype) @path = bank_dir @sample_type = stype @collections = [] Dir.children(bank_dir).each do |collection| collection_dir = @path + "/" + collection @collections << SampleCollection.new(collection_dir, collection) end end end class SampleCollection attr_reader :path, :name, :raw_files, :batches def initialize(col_dir, col_name) @path = col_dir @name = col_name @raw_files = Dir.children(col_dir) @batches = collate(@raw_files) end def collate(file_list) collated_batches = [] # 1440000 hits input/output error on MacOS Sonoma, 720000 does not # No, I have no idea why. Sometimes it works without issue. max_size = 1440000 current_batch = SampleBatch.new(max_size) file_list.each do |file| file_path = @path + "/" + file if current_batch.append(file_path) next else collated_batches << current_batch current_batch = SampleBatch.new(max_size) current_batch.append(file_path) end end collated_batches end end class SampleBatch attr_reader :max_size, :actual_size attr_accessor :files def initialize(max_size) @max_size = max_size @actual_size = 0 @files = [] end def append(file_path) file_size = File.size(file_path) if (@actual_size + file_size) > @max_size false else @files << file_path @actual_size += file_size true end end end SampleLibrary.new("/home/patrick/Music")
The script makes assumptions about paths and directory structure. The comments in the script detail this. The end-result is a floppies directory, containing a sample-type directory (such as 'drumloops'), containing directories for each collection (such as 'Best Service - Dance Mega Jungle Rave'), containing floppy images with names like 'DLBES001.IMG'.
These GOTEK drives seem fine with directory hierarchies, so it's not an issue if there's two drumloop collection folders that have their names reduced to 'DLBES'.
I did encounter an odd problem on MacOS in the initial draft of the script (as I tend to use Ocenaudio to chop samples). The first draft made use of diskutil and hdiutil to mount the images and change the FAT volume label. Pretty consistently I found that the closer I got to 1.44Mb, the more likely it would be for the copy to hit an input/output error.
Reducing the max size of batches to 720K made this go away (for the most part). But already working with limited space, I didn't feel like doubling the amount of floppy images I'd need to generate. Linux didn't have this issue at all. Although I did need to involve losetup as I couldn't find a way to change a FAT label without presenting the floppy image as a block device.
Surely there's a better way
Probably. I mentioned above there are additional cards that can be added to the SU700. One of these is the Yamaha XS532 SCSI board, which has a 50-pin header internally, and a 25-pin connector externally. This in combination with either a ZuluSCSI or BlueSCSI will give you (I think) up to four virtual hard-disks that are 8GB each.
That doesn't exactly solve the problem though. While it's all well and good we now have an 8GB psuedo-block-device we can store data on, we actually need to be able to mount it on a computer. Unfortunately the SU700 formats the HDD to a strange proprietary filesystem. Worse yet, the way it saves samples is entirely non-standard. Paul Winkler did some work in 2001 to figure out the file formats the SU700 actually exports, and got far enough it's possible to make an AIFF to Yamaha converter. But even then, that doesn't help us put files on the HDD.
One possibility is to abuse Blue/ZuluSCSI's ability to mount bin+cue/iso and the SU700's ability to read AKAI sample CDs. For all it wont let us export samples, 700MB is still nearly 500 times the storage space of a floppy. The formats AKAI uses are well documented, and tools exist to work with them.
Another possibility is to actually try to implement filesystem support in FUSE. Given their sample format is a modification of AIFF, I'd suspect their filesystem is a modification of either FAT or something else. I've ordered a BlueSCSI with the intent to at least dump a copy of a formatted HDD. Who knows, it might not be a lot of work.
Digitakt
Enjoying the SU700, I decided to look into the modern equivalent, which I'd say is the Elektron Digitakt. Of course, the moment I think about buying it, it gets discontinued and they announce (quite literally today) the Digitakt II. You can buy one from Elevator Sound, who are on my Recommended online stores list.I don't know if it's exactly the modern equivalent. It does quite a bit more (although strangely enough, lacks the very precise chopping of the SU700). But it's certainly within the same class of products.
AirPlay
Also, as an update to the AirPlay stuff - it's still crap. And I can confirm it isn't because of buffer-exhaustion as the latest beta of Finamp makes a point of filling the buffer with minutes of audio before playing.