Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #185 from ashbb/develop

Patches for Windows
  • Loading branch information...
commit ac5122bb175494c4756888950310e6ae11c06328 2 parents 53a1ab9 + 938e470
@wasnotrice wasnotrice authored
View
23 Rakefile
@@ -1,10 +1,17 @@
+$:.unshift '.'
+
+require 'rubygems'
require 'rake'
require 'rake/clean'
-# require_relative 'platform/skel'
+if RUBY_VERSION != '1.8.7'
+require_relative 'platform/skel'
+else
+require File.join(File.dirname(__FILE__), 'platform/skel')
+end
require 'fileutils'
require 'find'
-include FileUtils
require 'yaml'
+include FileUtils
YAML::ENGINE.yamler = 'syck' # Use Syck for backward compatibility
@@ -59,7 +66,9 @@ REVISION = (`#{GIT} rev-list HEAD`.split.length + 1).to_s
VERS = ENV['VERSION'] || "0.r#{REVISION}"
PKG = "#{NAME}-#{VERS}"
APPARGS = APP['run']
-FLAGS = %w[DEBUG]
+FLAGS = %w[DEBUG VIDEO]
+VLC_VERSION = (RUBY_PLATFORM =~ /win32/ ? "0.8": `vlc --version 2>/dev/null`.split[2])
+VLC_0_8 = VLC_VERSION !~ /^0\.9/
BIN = "*.{bundle,jar,o,so,obj,pdb,pch,res,lib,def,exp,exe,ilk}"
CLEAN.include ["{bin,shoes}/#{BIN}", "req/**/#{BIN}", "dist/**/*", "dist", "*.app"]
@@ -69,6 +78,10 @@ RUBY_V = RbConfig::CONFIG['ruby_version']
RUBY_LIB_BASE = File.basename(RbConfig::CONFIG['libdir'])
RUBY_PROGRAM_VERSION = RbConfig::CONFIG['RUBY_PROGRAM_VERSION']
SHOES_RUBY_ARCH = RbConfig::CONFIG['arch']
+RUBY_1_9 = (RUBY_V =~ /^1\.9/)
+if RUBY_1_9
+ $: << "."
+end
if ENV['APP']
%w[dmg icons].each do |subk|
@@ -135,8 +148,8 @@ end
task "dist/VERSION.txt" do |t|
File.open(t.name, 'w') do |f|
- f << %{shoes #{RELEASE_NAME.downcase} (0.r#{REVISION}) [#{SHOES_RUBY_ARCH} Ruby#{RUBY_PROGRAM_VERSION}]}
- %w[DEBUG].each { |x| f << " +#{x.downcase}" if ENV[x] }
+ f << %{shoes #{RELEASE_NAME.downcase} (0.r#{REVISION}) [#{RUBY_PLATFORM} Ruby#{RUBY_VERSION}]}
+ %w[VIDEO DEBUG].each { |x| f << " +#{x.downcase}" if ENV[x] }
f << "\n"
end
end
View
505 Rakefile.bk
@@ -0,0 +1,505 @@
+require 'rubygems'
+require 'rake'
+require 'rake/clean'
+# require_relative 'platform/skel'
+require 'fileutils'
+require 'find'
+require 'yaml'
+include FileUtils
+
+APP = YAML.load_file(File.join(ENV['APP'] || ".", "app.yaml"))
+APPNAME = APP['name']
+RELEASE_ID, RELEASE_NAME = APP['version'], APP['release']
+NAME = APP['shortname'] || APP['name'].downcase.gsub(/\W+/, '')
+SONAME = 'shoes'
+
+# Like puts, but only if we've --trace'd
+def vputs(str)
+ puts str if Rake.application.options.trace
+end
+
+begin
+require 'cucumber'
+require 'cucumber/rake/task'
+
+Cucumber::Rake::Task.new(:features) do |t|
+ t.cucumber_opts = "--format pretty"
+end
+
+rescue LoadError
+ vputs("Cukes is not loaded -- please `bundle install`")
+end
+
+begin
+
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new(:spec) do |t|
+ t.rspec_opts = ["--color"]
+end
+
+rescue LoadError
+ vputs("RSpec is not loaded -- please `bundle install`")
+end
+
+begin
+
+require 'bundler'
+Bundler::GemHelper.install_tasks
+
+rescue LoadError
+ vputs("Bundler is not loaded -- please `gem install bundler && bundle install`")
+end
+
+GIT = ENV['GIT'] || "git"
+REVISION = (`#{GIT} rev-list HEAD`.split.length + 1).to_s
+VERS = ENV['VERSION'] || "0.r#{REVISION}"
+PKG = "#{NAME}-#{VERS}"
+APPARGS = APP['run']
+FLAGS = %w[DEBUG]
+
+BIN = "*.{bundle,jar,o,so,obj,pdb,pch,res,lib,def,exp,exe,ilk}"
+CLEAN.include ["{bin,shoes}/#{BIN}", "req/**/#{BIN}", "dist", "*.app"]
+
+RUBY_SO = Config::CONFIG['RUBY_SO_NAME']
+RUBY_V = Config::CONFIG['ruby_version']
+RUBY_PROGRAM_VERSION = Config::CONFIG['RUBY_PROGRAM_VERSION']
+SHOES_RUBY_ARCH = Config::CONFIG['arch']
+
+if ENV['APP']
+ %w[dmg icons].each do |subk|
+ APP[subk].keys.each do |name|
+ APP[subk][name] = File.join(ENV['APP'], APP[subk][name])
+ end
+ end
+end
+
+if File.exists? ".git/refs/tags/#{RELEASE_ID}/#{RELEASE_NAME}"
+ abort "** Rename this release (and add to lib/shoes.rb) #{RELEASE_NAME} has already been tagged."
+end
+
+# Same effect as sourcing a shell script before running rake. It's necessary to
+# set these values before the make/{platform}/env.rb files are loaded.
+def osx_bootstrap_env
+ ENV['DYLD_LIBRARY_PATH'] = '/usr/local/Cellar/cairo/1.10.2/lib:/usr/local/Cellar/cairo/1.10.2/include/cairo'
+ ENV['LD_LIBRARY_PATH'] = '/usr/local/Cellar/cairo/1.10.2/lib:/usr/local/Cellar/cairo/1.10.2/include/cairo'
+ ENV['CAIRO_CFLAGS'] = '-I/usr/local/Cellar/cairo/1.10.2/include/cairo'
+ ENV['SHOES_DEPS_PATH'] = '/usr/local'
+end
+
+
+
+case RUBY_PLATFORM
+when /mingw/
+ require File.expand_path('rakefile_mingw')
+ Builder = MakeMinGW
+ NAMESPACE = :win32
+when /darwin/
+ osx_bootstrap_env
+ require File.expand_path('make/darwin/env')
+ require_relative "make/darwin/homebrew"
+
+ task :stub do
+ ENV['MACOSX_DEPLOYMENT_TARGET'] = '10.4'
+ sh "gcc -O -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc -framework Cocoa -o stub platform/mac/stub.m -I."
+ end
+ NAMESPACE = :osx
+when /linux/
+ require File.expand_path('rakefile_linux')
+ Builder = MakeLinux
+ NAMESPACE = :linux
+else
+ puts "Sorry, your platform [#{RUBY_PLATFORM}] is not supported..."
+end
+
+# --------------------------
+# common platform tasks
+
+desc "Same as `rake build'"
+task :default => [:build]
+
+desc "Does a full compile, with installer"
+task :package => [:build, :installer]
+
+task :build_os => [:build_skel, "dist/#{NAME}"]
+
+task "shoes/version.h" do |t|
+ File.open(t.name, 'w') do |f|
+ f << %{#define SHOES_RELEASE_ID #{RELEASE_ID}\n#define SHOES_RELEASE_NAME "#{RELEASE_NAME}"\n#define SHOES_REVISION #{REVISION}\n#define SHOES_BUILD_DATE #{Time.now.strftime("%Y%m%d")}\n#define SHOES_PLATFORM "#{SHOES_RUBY_ARCH}"\n}
+ end
+end
+
+task "dist/VERSION.txt" do |t|
+ File.open(t.name, 'w') do |f|
+ f << %{shoes #{RELEASE_NAME.downcase} (0.r#{REVISION}) [#{SHOES_RUBY_ARCH} Ruby#{RUBY_PROGRAM_VERSION}]}
+ %w[DEBUG].each { |x| f << " +#{x.downcase}" if ENV[x] }
+ f << "\n"
+ end
+end
+
+# shoes is small, if any include changes, go ahead and build from scratch.
+SRC.zip(OBJ).each do |c, o|
+ file o => [c] + Dir["shoes/*.h"]
+end
+
+# ------
+# skel
+
+def skel_replace(line)
+ line.gsub! /\s+%DEFAULTS%/ do
+ if APPARGS
+ args = APPARGS.split(/\s+/)
+ %{
+ char *default_argv[] = {argv[0], #{args.inspect[1..-2]}};
+ argv = default_argv;
+ argc = #{args.length + 1};
+ }
+ end
+ end
+ line
+end
+
+# preprocess .skel
+task :build_skel do |t|
+ Dir["bin/*.skel"].each do |src|
+ name = src.gsub(/\.skel$/, '.c')
+ File.open(src) do |skel|
+ File.open(name, 'w') do |c|
+ skel.each_line do |line|
+ c << skel_replace(line)
+ end
+ end
+ end
+ end
+end
+
+# --------------------------
+# tasks depending on Builder = MakeLinux|MakeDarwin|MakeMinGW
+
+desc "Does a full compile, for the OS you're running on"
+task :build => ["#{NAMESPACE}:build"]
+
+# first refactor ; build calls platform namespaced build;
+# for now, each of those calls the old build method.
+task :old_build => [:build_os, "dist/VERSION.txt"] do
+ Builder.common_build
+ Builder.copy_deps_to_dist
+ Builder.copy_files_to_dist
+ Builder.setup_system_resources
+end
+
+directory 'dist'
+
+task "dist/#{NAME}" => ["dist/lib#{SONAME}.#{DLEXT}", "bin/main.o"] + ADD_DLL + ["#{NAMESPACE}:make_app"]
+
+task "dist/lib#{SONAME}.#{DLEXT}" => ['shoes/version.h', 'dist'] + OBJ + ["#{NAMESPACE}:make_so"]
+
+def cc(t)
+ sh "#{CC} -I. -c -o #{t.name} #{LINUX_CFLAGS} #{t.source}"
+end
+
+rule ".o" => ".m" do |t|
+ cc t
+end
+
+rule ".o" => ".c" do |t|
+ cc t
+end
+
+desc "Generate an installer for the current platform"
+task :installer => ["#{NAMESPACE}:installer"]
+
+def rewrite before, after, reg = /\#\{(\w+)\}/, reg2 = '\1'
+ File.open(after, 'w') do |a|
+ File.open(before) do |b|
+ b.each do |line|
+ a << line.gsub(reg) do
+ if reg2.include? '\1'
+ reg2.gsub(%r!\\1!, Object.const_get($1))
+ else
+ reg2
+ end
+ end
+ end
+ end
+ end
+end
+
+def copy_files glob, dir
+ FileList[glob].each { |f| cp_r f, dir }
+end
+
+namespace :osx do
+ namespace :deps do
+ task :install => "homebrew:install"
+ namespace :homebrew do
+ desc "Install OS X dependencies using Homebrew"
+ task :install => [:customize, :install_libs, :uncustomize]
+
+ task :install_libs do
+ brew = Homebrew.new
+ brew.universal if ENV['SHOES_OSX_ARCH'] == "universal"
+ brew.install_packages
+ end
+
+ task :customize do
+ brew = Homebrew.new
+ brew.universal if ENV['SHOES_OSX_ARCH'] == "universal"
+ brew.add_custom_remote
+ brew.add_custom_formulas
+ end
+
+ task :uncustomize do
+ brew = Homebrew.new
+ brew.universal if ENV['SHOES_OSX_ARCH'] == "universal"
+ brew.remove_custom_formulas
+ brew.remove_custom_remote
+ end
+ end
+ end
+
+ task :build => ["build_tasks:pre_build", :build_skel, "dist/#{NAME}", "dist/VERSION.txt", "build_tasks:build"]
+
+ namespace :build_tasks do
+
+ task :build => [:common_build, :copy_deps_to_dist, :change_install_names, :copy_files_to_dist, :setup_system_resources, :verify]
+
+ # Make sure the installed ruby is capable of this build
+ task :check_ruby_arch do
+ build_arch, ruby_arch = [OSX_ARCH, Config::CONFIG['ARCH_FLAG']].map {|s| s.split.reject {|w| w.include?("arch")}}
+ if build_arch.length > 1 and build_arch.sort != ruby_arch.sort
+ abort("To build universal shoes, you must first install a universal ruby")
+ end
+ end
+
+ task :pre_build => :check_ruby_arch
+
+ def copy_ext_osx xdir, libdir
+ Dir.chdir(xdir) do
+ `ruby extconf.rb; make >/dev/null 2>&1`
+ end
+ copy_files "#{xdir}/*.bundle", libdir
+ end
+
+ task :common_build do
+ mkdir_p "dist/ruby"
+ cp_r "#{EXT_RUBY}/lib/ruby/#{RUBY_V}", "dist/ruby/lib"
+ unless ENV['STANDARD']
+ %w[soap wsdl xsd].each do |libn|
+ rm_rf "dist/ruby/lib/#{libn}"
+ end
+ end
+ %w[req/ftsearch/lib/* req/rake/lib/*].each do |rdir|
+ FileList[rdir].each { |rlib| cp_r rlib, "dist/ruby/lib" }
+ end
+ %w[req/binject/ext/binject_c req/ftsearch/ext/ftsearchrt req/chipmunk/ext/chipmunk].
+ each { |xdir| copy_ext_osx xdir, "dist/ruby/lib/#{SHOES_RUBY_ARCH}" }
+
+ gdir = "dist/ruby/gems/#{RUBY_V}"
+ {'hpricot' => 'lib', 'json' => 'lib/json/ext', 'sqlite3' => 'lib'}.each do |gemn, xdir|
+ spec = eval(File.read("req/#{gemn}/gemspec"))
+ mkdir_p "#{gdir}/specifications"
+ mkdir_p "#{gdir}/gems/#{spec.full_name}/lib"
+ FileList["req/#{gemn}/lib/*"].each { |rlib| cp_r rlib, "#{gdir}/gems/#{spec.full_name}/lib" }
+ mkdir_p "#{gdir}/gems/#{spec.full_name}/#{xdir}"
+ FileList["req/#{gemn}/ext/*"].each { |elib| copy_ext_osx elib, "#{gdir}/gems/#{spec.full_name}/#{xdir}" }
+ cp "req/#{gemn}/gemspec", "#{gdir}/specifications/#{spec.full_name}.gemspec"
+ end
+ end
+
+ def dylibs_to_change lib
+ `otool -L #{lib}`.split("\n").inject([]) do |dylibs, line|
+ if line =~ /^\S/ or line =~ /System|@executable_path|libobjc/
+ dylibs
+ else
+ dylibs << line.gsub(/\s\(compatibility.*$/, '').strip
+ end
+ end
+ end
+
+ task :change_install_names do
+ cd "dist" do
+ ["#{NAME}-bin", "pango-querymodules", *Dir['*.dylib'], *Dir['pango/modules/*.so']].each do |f|
+ sh "install_name_tool -id @executable_path/#{File.basename f} #{f}"
+ dylibs = dylibs_to_change(f)
+ dylibs.each do |dylib|
+ sh "install_name_tool -change #{dylib} @executable_path/#{File.basename dylib} #{f}"
+ end
+ end
+ end
+ end
+
+ task :copy_pango_modules_to_dist do
+ modules_file = `brew --prefix`.chomp << '/etc/pango/pango.modules'
+ modules_path = File.open(modules_file) {|f| f.grep(/^# ModulesPath = (.*)$/){$1}.first}
+ mkdir_p 'dist/pango'
+ cp_r modules_path, 'dist/pango'
+ cp `which pango-querymodules`.chomp, 'dist/'
+ end
+
+ task :copy_deps_to_dist => :copy_pango_modules_to_dist do
+ # Generate a list of dependencies straight from the generated files.
+ # Start with dependencies of shoes-bin and pango-querymodules, and then
+ # add the dependencies of those dependencies.
+ dylibs = dylibs_to_change("dist/#{NAME}-bin")
+ dylibs.concat dylibs_to_change("dist/pango-querymodules")
+ dupes = []
+ dylibs.each do |dylib|
+ dylibs_to_change(dylib).each do |d|
+ if dylibs.map {|lib| File.basename(lib)}.include?(File.basename(d))
+ dupes << d
+ else
+ dylibs << d
+ end
+ end
+ end
+ dylibs.each {|libn| cp "#{libn}", "dist/"}
+ end
+
+ task :copy_files_to_dist do
+ if ENV['APP']
+ if APP['clone']
+ sh APP['clone'].gsub(/^git /, "#{GIT} --git-dir=#{ENV['APP']}/.git ")
+ else
+ cp_r ENV['APP'], "dist/app"
+ end
+ if APP['ignore']
+ APP['ignore'].each do |nn|
+ rm_rf "dist/app/#{nn}"
+ end
+ end
+ end
+
+ cp_r "fonts", "dist/fonts"
+ cp_r "lib", "dist/lib"
+ cp_r "samples", "dist/samples"
+ cp_r "static", "dist/static"
+ cp "README.md", "dist/README.txt"
+ cp "CHANGELOG", "dist/CHANGELOG.txt"
+ cp "COPYING", "dist/COPYING.txt"
+ end
+
+ task :setup_system_resources do
+ rm_rf "#{APPNAME}.app"
+ mkdir "#{APPNAME}.app"
+ mkdir "#{APPNAME}.app/Contents"
+ cp_r "dist", "#{APPNAME}.app/Contents/MacOS"
+ mkdir "#{APPNAME}.app/Contents/Resources"
+ mkdir "#{APPNAME}.app/Contents/Resources/English.lproj"
+ sh "ditto \"#{APP['icons']['osx']}\" \"#{APPNAME}.app/App.icns\""
+ sh "ditto \"#{APP['icons']['osx']}\" \"#{APPNAME}.app/Contents/Resources/App.icns\""
+ rewrite "platform/mac/Info.plist", "#{APPNAME}.app/Contents/Info.plist"
+ cp "platform/mac/version.plist", "#{APPNAME}.app/Contents/"
+ rewrite "platform/mac/pangorc", "#{APPNAME}.app/Contents/MacOS/pangorc"
+ cp "platform/mac/command-manual.rb", "#{APPNAME}.app/Contents/MacOS/"
+ rewrite "platform/mac/shoes-launch", "#{APPNAME}.app/Contents/MacOS/#{NAME}-launch"
+ chmod 0755, "#{APPNAME}.app/Contents/MacOS/#{NAME}-launch"
+ chmod 0755, "#{APPNAME}.app/Contents/MacOS/#{NAME}-bin"
+ rewrite "platform/mac/shoes", "#{APPNAME}.app/Contents/MacOS/#{NAME}"
+ chmod 0755, "#{APPNAME}.app/Contents/MacOS/#{NAME}"
+ chmod_R 0755, "#{APPNAME}.app/Contents/MacOS/pango-querymodules"
+ # cp InfoPlist.strings YourApp.app/Contents/Resources/English.lproj/
+ `echo -n 'APPL????' > "#{APPNAME}.app/Contents/PkgInfo"`
+ end
+ end
+
+ desc "Verify the build products"
+ task :verify => ['verify:sanity', 'verify:lib_paths']
+
+ namespace :verify do
+ def report_error message
+ STDERR.puts "BUILD ERROR: " + message
+ end
+
+ task :sanity do
+ report_error "No #{APPNAME}.app file found" unless File.exist? "#{APPNAME}.app"
+ [NAME, "#{NAME}-launch", "#{NAME}-bin"].each do |f|
+ report_error "No #{f} file found" unless File.exist? "#{APPNAME}.app/Contents/MacOS/#{f}"
+ end
+ end
+
+ task :lib_paths do
+ cd "#{APPNAME}.app/Contents/MacOS" do
+ errors = []
+ ["#{NAME}-bin", "pango-querymodules", *Dir['*.dylib'], *Dir['pango/modules/*.so']].each do |f|
+ dylibs = dylibs_to_change(f)
+ dylibs.each do |dylib|
+ errors << "Suspect library path on #{f}:\n #{dylib}\n (check with `otool -L #{File.expand_path f}`)"
+ end
+ end
+ errors.each {|e| report_error e}
+ end
+ end
+ end
+
+ task :make_app do
+ # Builder.make_app "dist/#{NAME}"
+ bin = "dist/#{NAME}-bin"
+ rm_f "dist/#{NAME}"
+ rm_f bin
+ sh "#{CC} -Ldist -o #{bin} bin/main.o #{LINUX_LIBS} -lshoes #{OSX_ARCH}"
+ end
+
+ task :make_so do
+ name = "dist/lib#{SONAME}.#{DLEXT}"
+ ldflags = LINUX_LDFLAGS.sub! /INSTALL_NAME/, "-install_name @executable_path/lib#{SONAME}.#{DLEXT}"
+ sh "#{CC} -o #{name} #{OBJ.join(' ')} #{LINUX_LDFLAGS} #{LINUX_LIBS}"
+ %w[libpostproc.dylib libavformat.dylib libavcodec.dylib libavutil.dylib libruby.dylib].each do |libn|
+ sh "install_name_tool -change /tmp/dep/lib/#{libn} ./deps/lib/#{libn} #{name}"
+ end
+ end
+
+ task :installer do
+ dmg_ds, dmg_jpg = "platform/mac/dmg_ds_store", "static/shoes-dmg.jpg"
+ if APP['dmg']
+ dmg_ds, dmg_jpg = APP['dmg']['ds_store'], APP['dmg']['background']
+ end
+
+ mkdir_p "pkg"
+ rm_rf "dmg"
+ mkdir_p "dmg"
+ cp_r "#{APPNAME}.app", "dmg"
+ unless ENV['APP']
+ mv "dmg/#{APPNAME}.app/Contents/MacOS/samples", "dmg/samples"
+ end
+ ln_s "/Applications", "dmg/Applications"
+ sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/pango-querymodules"
+ sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/#{NAME}"
+ sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/#{NAME}-bin"
+ sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/#{NAME}-launch"
+ sh "DYLD_LIBRARY_PATH= platform/mac/pkg-dmg --target pkg/#{PKG}.dmg --source dmg --volname '#{APPNAME}' --copy #{dmg_ds}:/.DS_Store --mkdir /.background --copy #{dmg_jpg}:/.background" # --format UDRW"
+ rm_rf "dmg"
+ end
+end
+
+namespace :win32 do
+ task :build => [:old_build]
+
+ task :make_app do
+ Builder.make_app "dist/#{NAME}"
+ end
+
+ task :make_so do
+ Builder.make_so "dist/lib#{SONAME}.#{DLEXT}"
+ end
+
+ task :installer do
+ Builder.make_installer
+ end
+end
+
+namespace :linux do
+ task :build => [:old_build]
+
+ task :make_app do
+ Builder.make_app "dist/#{NAME}"
+ end
+
+ task :make_so do
+ Builder.make_so "dist/lib#{SONAME}.#{DLEXT}"
+ end
+
+ task :installer do
+ Builder.make_installer
+ end
+end
+
View
127 Rakefile_for_windows
@@ -0,0 +1,127 @@
+$:.unshift '.'
+
+require 'rubygems'
+require 'rake'
+require 'rake/clean'
+if RUBY_VERSION != '1.8.7'
+require_relative 'platform/skel'
+else
+require File.join(File.dirname(__FILE__), 'platform/skel')
+end
+require 'fileutils'
+require 'find'
+require 'yaml'
+include FileUtils
+
+APP = YAML.load_file(File.join(ENV['APP'] || ".", "app.yaml"))
+APPNAME = APP['name']
+RELEASE_ID, RELEASE_NAME = APP['version'], APP['release']
+NAME = APP['shortname'] || APP['name'].downcase.gsub(/\W+/, '')
+SONAME = 'shoes'
+
+GIT = ENV['GIT'] || "git"
+REVISION = (`#{GIT} rev-list HEAD`.split.length + 1).to_s
+VERS = ENV['VERSION'] || "0.r#{REVISION}"
+PKG = "#{NAME}-#{VERS}"
+APPARGS = APP['run']
+FLAGS = %w[DEBUG VIDEO]
+VLC_VERSION = (RUBY_PLATFORM =~ /win32/ ? "0.8": `vlc --version 2>/dev/null`.split[2])
+VLC_0_8 = VLC_VERSION !~ /^0\.9/
+
+BIN = "*.{bundle,jar,o,so,obj,pdb,pch,res,lib,def,exp,exe,ilk}"
+CLEAN.include ["{bin,shoes}/#{BIN}", "req/**/#{BIN}", "dist"]
+
+RUBY_SO = RbConfig::CONFIG['RUBY_SO_NAME']
+RUBY_V = RbConfig::CONFIG['ruby_version']
+RUBY_LIB_BASE = File.basename(RbConfig::CONFIG['libdir'])
+RUBY_PROGRAM_VERSION = RbConfig::CONFIG['RUBY_PROGRAM_VERSION']
+SHOES_RUBY_ARCH = RbConfig::CONFIG['arch']
+RUBY_1_9 = (RUBY_V =~ /^1\.9/)
+if RUBY_1_9
+ $: << "."
+end
+
+if ENV['APP']
+ %w[dmg icons].each do |subk|
+ APP[subk].keys.each do |name|
+ APP[subk][name] = File.join(ENV['APP'], APP[subk][name])
+ end
+ end
+end
+
+if File.exists? ".git/refs/tags/#{RELEASE_ID}/#{RELEASE_NAME}"
+ abort "** Rename this release (and add to lib/shoes.rb) #{RELEASE_NAME} has already been tagged."
+end
+
+case RUBY_PLATFORM
+when /mingw/
+ require File.expand_path('rakefile_mingw')
+ Builder = MakeMinGW
+when /darwin/
+ require File.expand_path('rakefile_darwin')
+ Builder = MakeDarwin
+when /linux/
+ require File.expand_path('rakefile_linux')
+ Builder = MakeLinux
+else
+ puts "Sorry, your platform [#{RUBY_PLATFORM}] is not supported..."
+end
+
+# --------------------------
+# common platform tasks
+
+desc "Same as `rake build'"
+task :default => [:build]
+
+desc "Does a full compile, with installer"
+task :package => [:build, :installer]
+
+task "shoes/version.h" do |t|
+ File.open(t.name, 'w') do |f|
+ f << %{#define SHOES_RELEASE_ID #{RELEASE_ID}\n#define SHOES_RELEASE_NAME "#{RELEASE_NAME}"\n#define SHOES_REVISION #{REVISION}\n#define SHOES_BUILD_DATE #{Time.now.strftime("%Y%m%d")}\n#define SHOES_PLATFORM "#{RUBY_PLATFORM}"\n}
+ end
+end
+
+task "dist/VERSION.txt" do |t|
+ File.open(t.name, 'w') do |f|
+ f << %{shoes #{RELEASE_NAME.downcase} (0.r#{REVISION}) [#{RUBY_PLATFORM} Ruby#{RUBY_VERSION}]}
+ %w[VIDEO DEBUG].each { |x| f << " +#{x.downcase}" if ENV[x] }
+ f << "\n"
+ end
+end
+
+# shoes is small, if any include changes, go ahead and build from scratch.
+SRC.zip(OBJ).each do |c, o|
+ file o => [c] + Dir["shoes/*.h"]
+end
+
+# --------------------------
+# tasks depending on Builder = MakeLinux|MakeDarwin|MakeMinGW
+
+desc "Does a full compile, for the OS you're running on"
+task :build => [:build_os, "dist/VERSION.txt"] do
+ Builder.common_build
+ Builder.copy_deps_to_dist
+ Builder.copy_files_to_dist
+ Builder.setup_system_resources
+end
+
+task "dist/#{NAME}" => ["dist/lib#{SONAME}.#{DLEXT}", "bin/main.o"] + ADD_DLL do |t|
+ Builder.make_app t.name
+end
+
+task "dist/lib#{SONAME}.#{DLEXT}" => ['shoes/version.h'] + OBJ do |t|
+ Builder.make_so t.name
+end
+
+rule ".o" => ".m" do |t|
+ Builder.cc t
+end
+
+rule ".o" => ".c" do |t|
+ Builder.cc t
+end
+
+task :installer do
+ Builder.make_installer
+end
View
2  app.yaml
@@ -1,5 +1,5 @@
name: Shoes
-version: 3
+version: 3.1
release: Policeman
icons:
win32: platform/msw/shoes.ico
View
35 lib/shoes.rb
@@ -4,32 +4,23 @@
# The Shoes base app, both a demonstration and the learning tool for
# using Shoes.
#
-ARGV.delete_if { |x| x =~ /-psn_/ }
-class Encoding
- %w[UTF_7 UTF_16BE UTF_16LE UTF_32BE UTF_32LE].each do |enc|
- eval "class #{enc};end" unless const_defined? enc.to_sym
- end
-end
+require 'shoes/encoding'
+
+ARGV.delete_if { |x| x =~ /-psn_/ }
require 'open-uri'
require 'optparse'
require 'resolv-replace' if RUBY_PLATFORM =~ /win/
-require_relative 'shoes/inspect'
-require_relative 'shoes/cache'
+require 'shoes/inspect'
+require 'shoes/cache'
if Object.const_defined? :Shoes
- require_relative 'shoes/image'
+ require 'shoes/image'
end
-require_relative 'shoes/shybuilder'
+require 'shoes/shybuilder'
def Shoes.hook; end
-class Encoding
- %w[ASCII_8BIT UTF_16BE UTF_16LE UTF_32BE UTF_32LE US_ASCII].each do |ec|
- eval "#{ec} = '#{ec.sub '_', '-'}'"
- end unless RUBY_PLATFORM =~ /linux/ or RUBY_PLATFORM =~ /darwin/
-end
-
class Range
def rand
conv = (Integer === self.end && Integer === self.begin ? :to_i : :to_f)
@@ -533,15 +524,15 @@ def tween opts, &blk
end
class Types::Widget
- @@types = {}
+ @types = {}
def self.inherited subc
methc = subc.to_s[/(^|::)(\w+)$/, 2].
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
- @@types[methc] = subc
+ @types[methc] = subc
Shoes.class_eval %{
def #{methc}(*a, &b)
- a.unshift Widget.class_variable_get("@@types")[#{methc.dump}]
+ a.unshift Widget.instance_variable_get("@types")[#{methc.dump}]
widget(*a, &b)
end
}
@@ -552,3 +543,9 @@ def #{methc}(*a, &b)
def window(*a, &b)
Shoes.app(*a, &b)
end
+
+class Object
+ %w[RELEASE_NAME RELEASE_ID REVISION VERSION RAD2PI TWO_PI HALF_PI PI VIDEO Link LinkHover].each do |v|
+ eval "#{v} = Shoes::#{v}"
+ end
+end
View
5 lib/shoes/encoding.rb
@@ -0,0 +1,5 @@
+# Only needed on windows (encoding.data not installed for linux/darwin)
+if RUBY_PLATFORM =~ /mswin|mingw/
+ IO.read(File.join DIR, 'encoding.data').
+ each_line{|file| require File.join(DIR, 'ruby/lib/i386-mingw32/enc', file.chomp)}
+end
View
2  lib/shoes/pack.rb
@@ -319,7 +319,7 @@ def self.linux(script, opt, &blk)
@exe = check
para "Windows"
end
- @incWin = list_box :items => items, :width => 0.6, :height => 30, do
+ @incWin = list_box :items => items, :width => 0.6, :height => 30 do
@downOpt = @incWin.text
est_recount
end
View
12 lib/shoes/setup.rb
@@ -52,7 +52,7 @@ def self.setup_app(setup)
end
start do
- @th =
+ @th =
Thread.start(self.app) do |app|
begin
setup.start(app)
@@ -69,7 +69,7 @@ def self.setup_app(setup)
fill black(0.2 - (i * 0.02))
strokewidth(3.0 - (i * 0.2))
stroke rgb(0.7, 0.7, 0.9, 1.0 - (i * 0.1))
- oval(@logo.left - i, @logo.top - i, @logo.width + (i * 2))
+ oval(@logo.left - i, @logo.top - i, @logo.width + (i * 2))
end
@pr.fraction = $fraction
if @script
@@ -322,19 +322,24 @@ def done
def initialize app
@title, @status, @prog, = app.slot.contents[-1].contents
end
+
def title msg
@title.replace msg
end
+
def progress count, total
#@prog.fraction = count.to_f / total.to_f
$fraction = count.to_f / total.to_f
end
+
def ask_yes_no msg
Kernel.confirm(msg)
end
+
def ask msg
Kernel.ask(msg)
end
+
def error msg, e
stat = @status
stat.app do
@@ -342,9 +347,11 @@ def error msg, e
stat.replace link("Error") { Shoes.show_log }, " ", msg
end
end
+
def say msg
@status.replace msg
end
+
def alert msg, quiz=nil
say(msg)
ask(quiz) if quiz
@@ -362,3 +369,4 @@ def method_missing(*args)
end
Shoes::Setup.init
+
View
4 make/make.rb
@@ -63,8 +63,8 @@ def common_build
%w[req/ftsearch/lib/* req/rake/lib/*].each do |rdir|
FileList[rdir].each { |rlib| cp_r rlib, "dist/ruby/lib" }
end
- %w[req/binject/ext/binject_c req/ftsearch/ext/ftsearchrt req/chipmunk/ext/chipmunk].
- each { |xdir| copy_ext xdir, "dist/ruby/lib/#{SHOES_RUBY_ARCH}" }
+ %w[req/binject/ext/binject_c req/ftsearch/ext/ftsearchrt req/bloopsaphone/ext/bloops req/chipmunk/ext/chipmunk].
+ each { |xdir| copy_ext xdir, "dist/ruby/lib/#{RUBY_PLATFORM}" }
gdir = "dist/ruby/gems/#{RUBY_V}"
{'hpricot' => 'lib', 'json' => 'lib/json/ext', 'sqlite3' => 'lib'}.each do |gemn, xdir|
View
33 make/mingw/env.rb
@@ -6,12 +6,20 @@
EXT_RUBY_LIB = "#{EXT_RUBY}/lib"
EXT_RUBY_LIBRUBY = "#{EXT_RUBY}/lib/ruby/#{RUBY_V}"
-# use the platform Ruby claims
-require 'rbconfig'
+# TODO: We really shouldn't perform actions just by including a file
+if ENV['VIDEO']
+ rm_rf "dist"
+ mkdir_p 'dist'
+ vlc_deps = '../deps_vlc_0.8'
+ copy_files vlc_deps + '/bin/plugins', 'dist'
+ cp_r vlc_deps + '/bin/libvlc.dll', EXT_RUBY + '/bin'
+ copy_files vlc_deps + '/include/vlc', EXT_RUBY + '/include'
+ copy_files vlc_deps + '/lib', EXT_RUBY
+end
CC = ENV['CC'] ? ENV['CC'] : "gcc"
file_list = ["shoes/*.c"] + %w{shoes/native/windows.c shoes/http/winhttp.c shoes/http/windownload.c}
-
+
SRC = FileList[*file_list]
OBJ = SRC.map do |x|
x.gsub(/\.\w+$/, '.o')
@@ -24,12 +32,19 @@
CAIRO_LIB = '-lcairo'
PANGO_CFLAGS = '-I/mingw/include/pango-1.0'
PANGO_LIB = '-lpangocairo-1.0 -lpango-1.0 -lpangoft2-1.0 -lpangowin32-1.0'
+if ENV['VIDEO']
+ VLC_CFLAGS = '-I/mingw/include/vlc'
+ VLC_LIB = '-llibvlc'
+else
+ VLC_CFLAGS = VLC_LIB = ''
+end
+
LINUX_CFLAGS = %[-Wall -I#{ENV['SHOES_DEPS_PATH'] || "/usr"}/include #{CAIRO_CFLAGS} #{PANGO_CFLAGS} -I#{RbConfig::CONFIG['archdir']}]
if RbConfig::CONFIG['rubyhdrdir']
LINUX_CFLAGS << " -I#{RbConfig::CONFIG['rubyhdrdir']} -I#{RbConfig::CONFIG['rubyhdrdir']}/#{SHOES_RUBY_ARCH}"
end
LINUX_LIB_NAMES = %W[#{RUBY_SO} cairo pangocairo-1.0 ungif]
-
+
FLAGS.each do |flag|
LINUX_CFLAGS << " -D#{flag}" if ENV[flag]
end
@@ -38,17 +53,17 @@
else
LINUX_CFLAGS << " -O "
end
-LINUX_CFLAGS << " -DRUBY_1_9"
+LINUX_CFLAGS << " -DRUBY_1_9" if RUBY_1_9
DLEXT = 'dll'
LINUX_CFLAGS << ' -I. -I/mingw/include'
-LINUX_CFLAGS << ' -I/mingw/include/ruby-1.9.1/ruby'
+LINUX_CFLAGS << ' -I/mingw/include/ruby-1.9.1/ruby' if RUBY_1_9
LINUX_CFLAGS << " -DXMD_H -DHAVE_BOOLEAN -DSHOES_WIN32 -D_WIN32_IE=0x0500 -D_WIN32_WINNT=0x0500 -DWINVER=0x0500 -DCOBJMACROS"
LINUX_LDFLAGS = " -DBUILD_DLL -lungif -ljpeg -lglib-2.0 -lgobject-2.0 -lgio-2.0 -lgmodule-2.0 -lgthread-2.0 -fPIC -shared"
LINUX_LDFLAGS << ' -lshell32 -lkernel32 -luser32 -lgdi32 -lcomdlg32 -lcomctl32 -lole32 -loleaut32 -ladvapi32 -loleacc -lwinhttp'
-
+LINUX_CFLAGS << " -DVLC_0_8" if ENV['VIDEO'] and VLC_0_8
cp APP['icons']['win32'], "shoes/appwin32.ico"
-
+
LINUX_LIBS = LINUX_LIB_NAMES.map { |x| "-l#{x}" }.join(' ')
-LINUX_LIBS << " -L#{RbConfig::CONFIG['libdir']} #{CAIRO_LIB} #{PANGO_LIB}"
+LINUX_LIBS << " -L#{RbConfig::CONFIG['libdir']} #{CAIRO_LIB} #{PANGO_LIB} #{VLC_LIB}"
View
8 make/mingw/tasks.rb
@@ -23,14 +23,20 @@ def copy_ext xdir, libdir
def copy_deps_to_dist
dlls = [RUBY_SO]
dlls += IO.readlines("make/mingw/dlls").map{|dll| dll.chomp}
+ dlls += %w{libvlc} if ENV['VIDEO']
dlls.each{|dll| cp "#{EXT_RUBY_BIN}/#{dll}.dll", "dist/"}
cp "dist/zlib1.dll", "dist/zlib.dll"
Dir.glob("../deps_cairo*/*"){|file| cp file, "dist/"}
sh "strip -x dist/*.dll" unless ENV['DEBUG']
end
-
+
def setup_system_resources
cp APP['icons']['gtk'], "dist/static/app-icon.png"
+ open 'dist/encoding.data', 'w' do |f|
+ Dir.chdir '../mingw/lib/ruby/1.9.1/i386-mingw32/enc' do
+ f.puts Dir["*.so", "*/*.so"]
+ end
+ end
end
def make_resource(t)
View
8 make/rakefile_common.rb
@@ -0,0 +1,8 @@
+task :build_os => [:buildenv_linux, :build_skel, "dist/#{NAME}"]
+
+task :buildenv_linux do
+ unless ENV['VIDEO']
+ rm_rf "dist"
+ mkdir_p "dist"
+ end
+end
View
1  rakefile_mingw.rb
@@ -1,3 +1,4 @@
+require File.expand_path('make/rakefile_common')
require File.expand_path('make/mingw/env')
require File.expand_path('make/mingw/tasks')
View
6 rakefile_mingw.rb.bk
@@ -0,0 +1,6 @@
+require File.expand_path('make/mingw/env')
+require File.expand_path('make/mingw/tasks')
+
+rule ".o" => ".rc" do |t|
+ MakeMinGW.make_resource t
+end
View
27 req/bloopsaphone/COPYING
@@ -0,0 +1,27 @@
+
+ :$: BLOOPSAPHONE :$:
+ Copyright (c) 2009 why the lucky stiff
+ Based on sfxr (c) 2007 Tomas Pettersson
+ (Also released under the MIT license)
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+ TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+ SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
+ OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
View
172 req/bloopsaphone/README
@@ -0,0 +1,172 @@
+
+ |~~ |~~
+ | |
+ :$: bloopsaphone :$:
+ `''''''''''''''''`
+
+ for writing chiptune-style songs
+ in c or ruby. you know: the sounds
+ of ataris, gameboys and the like.
+
+ ~
+
+ -$- ABOUT
+
+ this is a small c library for sending
+ chiptunes through portaudio, which is
+ a rather light cross-platform audio lib.
+ <http://www.portaudio.com/>
+
+ right now i'm only including ruby
+ bindings. you are welcome to contribute
+ code to hook up to other languages,
+ though.
+
+ i wrote this for h-ety h.
+ <http://hacketyhack.net/>
+
+ i don't have binaries ready for this yet,
+ so if you're on windows or os x, you may
+ have to wait until HH comes out at ART
+ AND CODE. the tribulations you face.
+
+ ~
+
+ -$- THE BLOOPSAPHONE THEME SONG
+ (in ruby)
+
+ require 'bloops'
+
+ # the bloops o' phone
+ b = Bloops.new
+ b.tempo = 320
+
+ # melodious
+ s1 = b.sound Bloops::SQUARE
+ s1.punch = 0.5
+ s1.sustain = 0.4
+ s1.decay = 0.2
+ s1.arp = 0.4
+ s1.aspeed = 0.6
+ s1.repeat = 0.6
+ s1.phase = 0.2
+ s1.psweep = 0.2
+
+ # beats
+ s2 = b.sound Bloops::NOISE
+ s2.punch = 0.5
+ s2.sustain = 0.2
+ s2.decay = 0.4
+ s2.slide = -0.4
+ s2.phase = 0.2
+ s2.psweep = 0.2
+
+ # the tracks
+ b.tune s1, "f#5 c6 e4 b6 g5 d6 4 f#5 e5 c5 b6 c6 d6 4 "
+ b.tune s2, "4 c6 4 b5 4 4 e4 4 c6 4 b5 4 4 e4"
+
+ # and away we go
+ b.play
+ sleep 1 while !b.stopped?
+
+ ~
+
+ -$- BUILDING FOR RUBY
+
+ If Ruby is in your path and PortAudio 1.9
+ or greater is installed:
+
+ make ruby
+
+ To install PortAudio 1.9 under Ubuntu:
+
+ aptitude install portaudio19-dev
+
+ To build from source isn't too bad.
+ Download PortAudio 1.9 and build it.
+ <http://www.portaudio.com/archives/pa_stable_v19_20071207.tar.gz>
+
+ Like this:
+
+ $ tar xzvf pa_stable_v19_20071207.tar.gz
+ $ cd portaudio
+ $ ./configure
+ $ make
+ $ sudo make install
+
+ Then go back to Bloopsaphone and do
+ a `make ruby`.
+
+ ~
+
+ -$- THE IDEALS,
+
+ -1- ASYNCHRONOUS.
+ You send it a song and it plays in
+ the background. You'll get an event
+ when it finishes.
+
+ -2- SMALL.
+ This is just a toy, I don't want it
+ to be very big and comprehensive.
+ Just to play little tunes with a
+ nostalgic arcade sound rather than
+ the CASIO-stylings of most MIDI.
+
+ -3- CUSTOM NOTATION.
+ Someone told me about Nokring, iMelody,
+ numbered musical notation and I did
+ some reading. They're little languages
+ for texting yourself a ringtone.
+
+ <http://en.wikipedia.org/wiki/Ring_Tone_Transfer_Language>
+ <http://homepage.mac.com/alvinmok/ericsson/emelody.html>
+
+ Bloopsaphone uses a variation on RTTTL.
+
+ Instead of commas, I use whitespace.
+ A rest is simply a number. A plus sign
+ moves everything up an octave. A minus
+ down an octave.
+
+ The Simpsons' Theme, for instance, would be:
+
+ 32 + C E F# 8:A G E C - 8:A 8:F# 8:F# 8:F# 2:G
+
+ Which translates into:
+
+ * a 1/32nd note rest.
+ * change one octave up.
+ * C quarter note.
+ * E quarter note.
+ * F# quarter note.
+ * A eighth note.
+ * G quarter.
+ * E quarter.
+ * C one-quarter note.
+ * change one octave down.
+ * A eighth.
+ * Three F# eighths.
+ * G half note.
+
+ The colons are optional. They are there because you
+ can place an octave number after each note. Somehow
+ "8B6" (an eighth note of B at the sixth octave) looks
+ more confusing than "8:B6". I guess I figured that
+ the timing "8" is conceptually separate from the
+ actual tone "B6", even though they both comprise
+ the note itself.
+
+ -4- SERIALIZE SOUNDS.
+ To accomodate passing instruments between
+ ruby and c, bloopsaphone comes with a tiny
+ file format for describing sounds.
+
+ You can find examples of these in the sounds/
+ folder in this distro. Possible sound types
+ are 'square', 'sawtooth', 'sine' and 'noise'.
+ All other settings go from 0.0 to 1.0.
+
+ The 'freq' setting is only used if the sound
+ is played without a tune.
+
View
504 req/bloopsaphone/c/bloopsaphone.c
@@ -0,0 +1,504 @@
+//
+// bloopsaphone.c
+// the chiptune maker for portaudio
+// (with bindings for ruby)
+//
+// (c) 2009 why the lucky stiff
+// See COPYING for the license
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include <portaudio.h>
+#include <unistd.h>
+#include "bloopsaphone.h"
+
+#ifdef PaStream
+#error ** Looks like you're linking against PortAudio 1.8!
+#error ** Bloopsaphone needs PortAudio 1.9 or greater.
+#error ** On Ubuntu, try: aptitude install portaudio19-dev.
+#endif
+
+#define SAMPLE_RATE 44100
+#define rnd(n) (rand() % (n + 1))
+#define tempo2frames(tempo) ((float)SAMPLE_RATE / (tempo / 60.0f))
+#define PI 3.14159265f
+
+static bloopsmix *MIXER = NULL;
+
+static void bloops_synth(int, float *);
+static int bloops_port_callback(const void *, void *,
+ unsigned long, const PaStreamCallbackTimeInfo *,
+ PaStreamCallbackFlags, void *);
+
+float
+frnd(float range)
+{
+ return (float)rnd(10000) / 10000 * range;
+}
+
+static void
+bloops_remove(bloops *B)
+{
+ int i;
+ if (MIXER == NULL) return;
+ for (i = 0; i < BLOOPS_MAX_CHANNELS; i++)
+ if (MIXER->B[i] == B)
+ MIXER->B[i] = NULL;
+}
+
+void
+bloops_ready(bloops *B, bloopsatrack *A, unsigned char init)
+{
+ A->period = 100.0 / (A->P->freq * A->P->freq + 0.001);
+ A->maxperiod = 100.0 / (A->P->limit * A->P->limit + 0.001);
+ A->slide = 1.0 - pow((double)A->P->slide, 3.0) * 0.01;
+ A->dslide = -pow((double)A->P->dslide, 3.0) * 0.000001;
+ A->square = 0.5f - A->P->square * 0.5f;
+ A->sweep = -A->P->sweep * 0.00005f;
+ if (A->P->arp >= 0.0f)
+ A->arp = 1.0 - pow((double)A->P->arp, 2.0) * 0.9;
+ else
+ A->arp = 1.0 + pow((double)A->P->arp, 2.0) * 10.0;
+ A->atime = 0;
+ A->alimit = (int)(pow(1.0f - A->P->aspeed, 2.0f) * 20000 + 32);
+ if (A->P->aspeed == 1.0f)
+ A->alimit = 0;
+
+ if (init)
+ {
+ int i = 0;
+ A->phase = 0;
+ A->filter[0] = 0.0f;
+ A->filter[1] = 0.0f;
+ A->filter[2] = pow(A->P->lpf, 3.0f) * 0.1f;
+ A->filter[3] = 1.0f + A->P->lsweep * 0.0001f;
+ A->filter[4] = 5.0f / (1.0f + pow(A->P->resonance, 2.0f) * 20.0f) * (0.01f + A->filter[2]);
+ if (A->filter[4] > 0.8f) A->filter[4] = 0.8f;
+ A->filter[5] = 0.0f;
+ A->filter[6] = pow(A->P->hpf, 2.0f) * 0.1f;
+ A->filter[7] = 1.0 + A->P->hsweep * 0.0003f;
+
+ A->vibe = 0.0f;
+ A->vspeed = pow(A->P->vspeed, 2.0f) * 0.01f;
+ A->vdelay = A->P->vibe * 0.5f;
+
+ A->volume = 0.0f;
+ A->stage = 0;
+ A->time = 0;
+ A->length[0] = (int)(A->P->attack * A->P->attack * 100000.0f);
+ A->length[1] = (int)(A->P->sustain * A->P->sustain * 100000.0f);
+ A->length[2] = (int)(A->P->decay * A->P->decay * 100000.0f);
+
+ A->fphase = pow(A->P->phase, 2.0f) * 1020.0f;
+ if (A->P->phase < 0.0f) A->fphase = -A->fphase;
+ A->dphase = pow(A->P->psweep, 2.0f) * 1.0f;
+ if (A->P->psweep < 0.0f) A->dphase = -A->dphase;
+ A->iphase = abs((int)A->fphase);
+ A->phasex = 0;
+
+ memset(A->phaser, 0, 1024 * sizeof(float));
+ for (i = 0; i < 32; i++)
+ A->noise[i] = frnd(2.0f) - 1.0f;
+
+ A->repeat = 0;
+ A->limit = (int)(pow(1.0f - A->P->repeat, 2.0f) * 20000 + 32);
+ if (A->P->repeat == 0.0f)
+ A->limit = 0;
+ A->playing = BLOOPS_PLAY;
+ }
+}
+
+void
+bloops_clear(bloops *B)
+{
+ int i;
+ for (i = 0; i < BLOOPS_MAX_TRACKS; i++)
+ B->tracks[i] = NULL;
+}
+
+void
+bloops_tempo(bloops *B, int tempo)
+{
+ B->tempo = tempo;
+}
+
+void
+bloops_track_at(bloops *B, bloopsatrack *track, int num)
+{
+ B->tracks[num] = track;
+}
+
+int
+bloops_is_done(bloops *B)
+{
+ return B->play == BLOOPS_STOP;
+}
+
+static void
+bloops_synth(int length, float* buffer)
+{
+ int bi, t, i, si;
+
+ while (length--)
+ {
+ int samplecount = 0;
+ float allsample = 0.0f;
+
+ for (bi = 0; bi < BLOOPS_MAX_CHANNELS; bi++)
+ {
+ int moreframes = 0;
+ bloops *B = MIXER->B[bi];
+ if (B == NULL || B->play == BLOOPS_STOP)
+ continue;
+ for (t = 0; t < BLOOPS_MAX_TRACKS; t++)
+ {
+ bloopsatrack *A = B->tracks[t];
+ if (A == NULL)
+ continue;
+
+ if (A->notes)
+ {
+ if (A->frames == A->nextnote[0])
+ {
+ if (A->nextnote[1] < A->nlen)
+ {
+ bloopsanote *note = &A->notes[A->nextnote[1]];
+ float freq = A->P->freq;
+ if (note->tone != 'n')
+ freq = bloops_note_freq(note->tone, (int)note->octave);
+ if (freq == 0.0f) {
+ A->period = 0.0f;
+ A->playing = BLOOPS_STOP;
+ } else {
+ bloops_ready(B, A, 1);
+ A->period = 100.0 / (freq * freq + 0.001);
+ }
+
+ A->nextnote[0] += (int)(tempo2frames(B->tempo) * (4.0f / note->duration));
+ }
+ A->nextnote[1]++;
+ }
+
+ if (A->nextnote[1] <= A->nlen)
+ moreframes++;
+ }
+ else
+ {
+ moreframes++;
+ }
+
+ A->frames++;
+
+ if (A->playing == BLOOPS_STOP)
+ continue;
+
+ samplecount++;
+ A->repeat++;
+ if (A->limit != 0 && A->repeat >= A->limit)
+ {
+ A->repeat = 0;
+ bloops_ready(B, A, 0);
+ }
+
+ A->atime++;
+ if (A->alimit != 0 && A->atime >= A->alimit)
+ {
+ A->alimit = 0;
+ A->period *= A->arp;
+ }
+
+ A->slide += A->dslide;
+ A->period *= A->slide;
+ if (A->period > A->maxperiod)
+ {
+ A->period = A->maxperiod;
+ if (A->P->limit > 0.0f)
+ A->playing = BLOOPS_STOP;
+ }
+
+ float rfperiod = A->period;
+ if (A->vdelay > 0.0f)
+ {
+ A->vibe += A->vspeed;
+ rfperiod = A->period * (1.0 + sin(A->vibe) * A->vdelay);
+ }
+
+ int period = (int)rfperiod;
+ if (period < 8) period = 8;
+ A->square += A->sweep;
+ if(A->square < 0.0f) A->square = 0.0f;
+ if(A->square > 0.5f) A->square = 0.5f;
+
+ A->time++;
+ if (A->time > A->length[A->stage])
+ {
+ A->time = 0;
+ A->stage++;
+ if (A->stage == 3)
+ A->playing = BLOOPS_STOP;
+ }
+
+ switch (A->stage) {
+ case 0:
+ A->volume = (float)A->time / A->length[0];
+ break;
+ case 1:
+ A->volume = 1.0f + pow(1.0f - (float)A->time / A->length[1], 1.0f) * 2.0f * A->P->punch;
+ break;
+ case 2:
+ A->volume = 1.0f - (float)A->time / A->length[2];
+ break;
+ }
+
+ A->fphase += A->dphase;
+ A->iphase = abs((int)A->fphase);
+ if (A->iphase > 1023) A->iphase = 1023;
+
+ if (A->filter[7] != 0.0f)
+ {
+ A->filter[6] *= A->filter[7];
+ if (A->filter[6] < 0.00001f) A->filter[6] = 0.00001f;
+ if (A->filter[6] > 0.1f) A->filter[6] = 0.1f;
+ }
+
+ float ssample = 0.0f;
+ for (si = 0; si < 8; si++)
+ {
+ float sample = 0.0f;
+ A->phase++;
+ if (A->phase >= period)
+ {
+ A->phase %= period;
+ if (A->P->type == BLOOPS_NOISE)
+ for (i = 0; i < 32; i++)
+ A->noise[i] = frnd(2.0f) - 1.0f;
+ }
+
+ float fp = (float)A->phase / period;
+ switch (A->P->type)
+ {
+ case BLOOPS_SQUARE:
+ if (fp < A->square)
+ sample = 0.5f;
+ else
+ sample = -0.5f;
+ break;
+ case BLOOPS_SAWTOOTH:
+ sample = 1.0f - fp * 2;
+ break;
+ case BLOOPS_SINE:
+ sample = (float)sin(fp * 2 * PI);
+ break;
+ case BLOOPS_NOISE:
+ sample = A->noise[A->phase * 32 / period];
+ break;
+ }
+
+ float pp = A->filter[0];
+ A->filter[2] *= A->filter[3];
+ if (A->filter[2] < 0.0f) A->filter[2] = 0.0f;
+ if (A->filter[2] > 0.1f) A->filter[2] = 0.1f;
+ if (A->P->lpf != 1.0f)
+ {
+ A->filter[1] += (sample - A->filter[0]) * A->filter[2];
+ A->filter[1] -= A->filter[1] * A->filter[4];
+ }
+ else
+ {
+ A->filter[0] = sample;
+ A->filter[1] = 0.0f;
+ }
+ A->filter[0] += A->filter[1];
+
+ A->filter[5] += A->filter[0] - pp;
+ A->filter[5] -= A->filter[5] * A->filter[6];
+ sample = A->filter[5];
+
+ A->phaser[A->phasex & 1023] = sample;
+ sample += A->phaser[(A->phasex - A->iphase + 1024) & 1023];
+ A->phasex = (A->phasex + 1) & 1023;
+
+ ssample += sample * A->volume;
+ }
+ ssample = ssample / 8 * B->volume;
+ ssample *= 2.0f * A->P->volume;
+
+ if (ssample > 1.0f) ssample = 1.0f;
+ if (ssample < -1.0f) ssample = -1.0f;
+ allsample += ssample;
+ }
+ if (moreframes == 0)
+ B->play = BLOOPS_STOP;
+ }
+
+ *buffer++ = allsample;
+ }
+}
+
+static int bloops_port_callback(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+ PaStreamCallbackFlags statusFlags, void *data)
+{
+ int i;
+ float *out = (float*)outputBuffer;
+ bloops *B = (bloops *)data;
+ bloops_synth(framesPerBuffer, out);
+ return paContinue;
+}
+
+void
+bloops_play(bloops *B)
+{
+ int i;
+
+ for (i = 0; i < BLOOPS_MAX_TRACKS; i++)
+ if (B->tracks[i] != NULL) {
+ bloops_ready(B, B->tracks[i], 1);
+ B->tracks[i]->frames = 0;
+ B->tracks[i]->nextnote[0] = 0;
+ B->tracks[i]->nextnote[1] = 0;
+ }
+
+ bloops_remove(B);
+ for (i = 0; i < BLOOPS_MAX_CHANNELS; i++)
+ if (MIXER->B[i] == NULL || MIXER->B[i]->play == BLOOPS_STOP) {
+ MIXER->B[i] = B;
+ break;
+ }
+
+ B->play = BLOOPS_PLAY;
+ if (MIXER->stream == NULL) {
+ Pa_OpenDefaultStream(&MIXER->stream, 0, 1, paFloat32,
+ SAMPLE_RATE, 512, bloops_port_callback, B);
+ Pa_StartStream(MIXER->stream);
+ }
+}
+
+void
+bloops_stop(bloops *B)
+{
+ int i, stopall = 1;
+ B->play = BLOOPS_STOP;
+ for (i = 0; i < BLOOPS_MAX_CHANNELS; i++)
+ if (MIXER->B[i] != NULL && MIXER->B[i]->play != BLOOPS_STOP)
+ stopall = 0;
+
+ if (stopall)
+ {
+ Pa_StopStream(MIXER->stream);
+ Pa_CloseStream(MIXER->stream);
+ MIXER->stream = NULL;
+ }
+}
+
+bloopsaphone *
+bloops_square()
+{
+ bloopsaphone *P = (bloopsaphone *)calloc(sizeof(bloopsaphone), 1);
+ P->type = BLOOPS_SQUARE;
+ P->volume = 0.5f;
+ P->sustain = 0.3f;
+ P->decay = 0.4f;
+ P->freq = 0.3f;
+ P->lpf = 1.0f;
+ return P;
+}
+
+bloopsaphone *
+bloops_load(char* filename)
+{
+ bloopsaphone *P = NULL;
+ FILE* file = fopen(filename, "rb");
+ if (!file) return NULL;
+
+ int version = 0;
+ fread(&version, 1, sizeof(int), file);
+ if (version != 102)
+ return NULL;
+
+ P = (bloopsaphone *)malloc(sizeof(bloopsaphone));
+ fread(&P->type, 1, sizeof(int), file);
+
+ P->volume = 0.5f;
+ fread(&P->volume, 1, sizeof(float), file);
+ fread(&P->freq, 1, sizeof(float), file);
+ fread(&P->limit, 1, sizeof(float), file);
+ fread(&P->slide, 1, sizeof(float), file);
+ fread(&P->dslide, 1, sizeof(float), file);
+ fread(&P->square, 1, sizeof(float), file);
+ fread(&P->sweep, 1, sizeof(float), file);
+
+ fread(&P->vibe, 1, sizeof(float), file);
+ fread(&P->vspeed, 1, sizeof(float), file);
+ fread(&P->vdelay, 1, sizeof(float), file);
+
+ fread(&P->attack, 1, sizeof(float), file);
+ fread(&P->sustain, 1, sizeof(float), file);
+ fread(&P->decay, 1, sizeof(float), file);
+ fread(&P->punch, 1, sizeof(float), file);
+
+ fread(&P->resonance, 1, sizeof(float), file);
+ fread(&P->lpf, 1, sizeof(float), file);
+ fread(&P->lsweep, 1, sizeof(float), file);
+ fread(&P->hpf, 1, sizeof(float), file);
+ fread(&P->hsweep, 1, sizeof(float), file);
+
+ fread(&P->phase, 1, sizeof(float), file);
+ fread(&P->psweep, 1, sizeof(float), file);
+
+ fread(&P->repeat, 1, sizeof(float), file);
+ fread(&P->arp, 1, sizeof(float), file);
+ fread(&P->aspeed, 1, sizeof(float), file);
+
+ fclose(file);
+ return P;
+}
+
+static int bloops_open = 0;
+
+bloops *
+bloops_new()
+{
+ bloops *B = (bloops *)malloc(sizeof(bloops));
+ B->volume = 0.10f;
+ B->tempo = 120;
+ B->play = BLOOPS_STOP;
+ bloops_clear(B);
+
+ if (MIXER == NULL)
+ MIXER = (bloopsmix *)calloc(sizeof(bloopsmix), 1);
+
+ if (!bloops_open++)
+ {
+ srand(time(NULL));
+ Pa_Initialize();
+ }
+
+ return B;
+}
+
+void
+bloops_destroy(bloops *B)
+{
+ bloops_remove(B);
+ free((void *)B);
+
+ if (!--bloops_open)
+ {
+ Pa_Terminate();
+ if (MIXER != NULL)
+ free(MIXER);
+ MIXER = NULL;
+ }
+}
+
+void
+bloops_track_destroy(bloopsatrack *track)
+{
+ if (track->notes != NULL)
+ free(track->notes);
+ free(track);
+}
View
100 req/bloopsaphone/c/bloopsaphone.h
@@ -0,0 +1,100 @@
+//
+// bloopsaphone.h
+// the chiptune maker for portaudio
+//
+#ifndef BLOOPSAPHONE_H
+#define BLOOPSAPHONE_H
+
+#define BLOOPSAPHONE_VERSION "1.0"
+
+#define BLOOPS_STOP 0
+#define BLOOPS_PLAY 1
+#define BLOOPS_MUTE 2
+
+#define BLOOPS_SQUARE 0
+#define BLOOPS_SAWTOOTH 1
+#define BLOOPS_SINE 2
+#define BLOOPS_NOISE 3
+
+typedef struct {
+ unsigned char type, pan;
+ float volume;
+ float punch;
+ float attack;
+ float sustain;
+ float decay;
+ float freq, limit, slide, dslide; // pitch
+ float square, sweep; // square wave
+ float vibe, vspeed, vdelay; // vibrato
+ float lpf, lsweep, resonance, hpf, hsweep;
+ // hi-pass, lo-pass
+ float arp, aspeed; // arpeggiator
+ float phase, psweep; // phaser
+ float repeat; // repeats?
+} bloopsaphone;
+
+#define BLOOPS_HI_OCTAVE 8
+
+typedef struct {
+ char tone, octave, duration;
+} bloopsanote;
+
+typedef struct {
+ bloopsaphone *P;
+ int nlen, capa;
+ bloopsanote *notes;
+
+ int frames, nextnote[2];
+ float volume, freq;
+ unsigned char playing;
+ int stage, time, length[3];
+ double period, maxperiod, slide, dslide;
+ float square, sweep;
+ int phase, iphase, phasex;
+ float fphase, dphase;
+ float phaser[1024];
+ float noise[32];
+ float filter[8];
+ float vibe, vspeed, vdelay;
+ int repeat, limit;
+ double arp;
+ int atime, alimit;
+} bloopsatrack;
+
+#define BLOOPS_MAX_TRACKS 64
+#define BLOOPS_MAX_CHANNELS 64
+
+typedef struct {
+ int tempo;
+ float volume;
+ bloopsatrack *tracks[BLOOPS_MAX_TRACKS];
+ unsigned char play;
+} bloops;
+
+typedef struct {
+ bloops *B[BLOOPS_MAX_CHANNELS];
+ void *stream;
+} bloopsmix;
+
+//
+// the api
+//
+bloops *bloops_new();
+void bloops_destroy(bloops *);
+bloopsaphone *bloops_square();
+bloopsaphone *bloops_load(char *);
+void bloops_clear(bloops *);
+void bloops_tempo(bloops *, int tempo);
+void bloops_track_at(bloops *, bloopsatrack *, int);
+void bloops_track_destroy(bloopsatrack *);
+void bloops_play(bloops *);
+void bloops_stop(bloops *);
+int bloops_is_done(bloops *);
+bloopsatrack *bloops_track(bloops *, bloopsaphone *, char *, int);
+bloopsatrack *bloops_track2(bloops *, bloopsaphone *, char *);
+char *bloops_track_str(bloopsatrack *);
+float bloops_note_freq(char, int);
+bloopsaphone *bloops_sound_file(bloops *, char *);
+char *bloops_sound_str(bloops *, bloopsaphone *);
+
+#endif
View
1,209 req/bloopsaphone/c/notation.c
@@ -0,0 +1,1209 @@
+#line 1 "c/notation.rl"
+//
+// notation.rl
+// the musical notation parser
+//
+// (c) 2009 why the lucky stiff
+// See COPYING for the license
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <sys/stat.h>
+#include "bloopsaphone.h"
+
+#define ATOI(X,N) ({ \
+ char *Ap = X; \
+ int Ai = 0; \
+ size_t Al = N; \
+ while (Al--) { \
+ if ((*Ap >= '0') && (*Ap <= '9')) { \
+ Ai = (Ai * 10) + (*Ap - '0'); \
+ Ap++; \
+ } \
+ else break; \
+ } \
+ Ai; \
+})
+
+#define NOTE S->notes[S->nlen]
+
+#define NEXT() \
+ NOTE.duration = len; \
+ NOTE.octave = oct; \
+ mod = 0; \
+ tone = 0; \
+ len = 4; \
+ S->nlen++
+
+
+#line 42 "c/notation.c"
+static const char _bloopnotes_actions[] = {
+ 0, 1, 0, 1, 3, 1, 4, 1,
+ 5, 1, 6, 1, 7, 1, 8, 1,
+ 9, 2, 0, 10, 2, 0, 12, 2,
+ 0, 13, 2, 3, 12, 2, 4, 13,
+ 3, 1, 2, 11, 3, 5, 2, 11,
+ 3, 6, 2, 11
+};
+
+static const char _bloopnotes_key_offsets[] = {
+ 0, 0, 11, 13, 16, 17, 17, 19,
+ 22, 23, 23, 30, 35, 39, 43, 45
+};
+
+static const char _bloopnotes_trans_keys[] = {
+ 32, 43, 45, 9, 13, 49, 57, 65,
+ 71, 97, 103, 49, 57, 58, 48, 57,
+ 58, 49, 57, 58, 48, 57, 58, 58,
+ 48, 57, 65, 71, 97, 103, 58, 65,
+ 71, 97, 103, 65, 71, 97, 103, 35,
+ 98, 49, 56, 49, 56, 0
+};
+
+static const char _bloopnotes_single_lengths[] = {
+ 0, 3, 0, 1, 1, 0, 0, 1,
+ 1, 0, 1, 1, 0, 2, 0, 0
+};
+
+static const char _bloopnotes_range_lengths[] = {
+ 0, 4, 1, 1, 0, 0, 1, 1,
+ 0, 0, 3, 2, 2, 1, 1, 0
+};
+
+static const char _bloopnotes_index_offsets[] = {
+ 0, 0, 8, 10, 13, 15, 16, 18,
+ 21, 23, 24, 29, 33, 36, 40, 42
+};
+
+static const char _bloopnotes_trans_targs[] = {
+ 1, 2, 6, 1, 10, 13, 13, 0,
+ 3, 1, 5, 4, 1, 5, 1, 1,
+ 7, 1, 9, 8, 1, 9, 1, 1,
+ 12, 11, 13, 13, 1, 12, 13, 13,
+ 1, 13, 13, 1, 14, 14, 15, 1,
+ 15, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0
+};
+
+static const char _bloopnotes_trans_actions[] = {
+ 15, 0, 0, 15, 0, 0, 0, 0,
+ 3, 26, 0, 0, 20, 0, 20, 20,
+ 5, 29, 0, 0, 23, 0, 23, 23,
+ 0, 0, 1, 1, 17, 0, 1, 1,
+ 17, 1, 1, 17, 9, 9, 9, 40,
+ 7, 36, 32, 26, 20, 20, 20, 29,
+ 23, 23, 23, 17, 17, 17, 40, 36,
+ 32, 0
+};
+
+static const char _bloopnotes_to_state_actions[] = {
+ 0, 11, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const char _bloopnotes_from_state_actions[] = {
+ 0, 13, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const char _bloopnotes_eof_trans[] = {
+ 0, 0, 44, 47, 47, 47, 48, 51,
+ 51, 51, 54, 54, 54, 55, 56, 57
+};
+
+static const int bloopnotes_start = 1;
+static const int bloopnotes_error = 0;
+
+static const int bloopnotes_en_main = 1;
+
+#line 109 "c/notation.rl"
+
+
+bloopsatrack *
+bloops_track(bloops *B, bloopsaphone *P, char *track, int tracklen)
+{
+ int cs, act, oct = 4, len = 4;
+ bloopsatrack *S = (bloopsatrack *)malloc(sizeof(bloopsatrack));
+ char tone, mod, *p, *pe, *ts, *te, *eof = 0;
+
+ S->P = P;
+ S->nlen = 0;
+ S->capa = 1024;
+ S->notes = (bloopsanote *)calloc(sizeof(bloopsanote), 1024);
+
+ p = track;
+ pe = track + tracklen + 1;
+
+
+#line 142 "c/notation.c"
+ {
+ cs = bloopnotes_start;
+ ts = 0;
+ te = 0;
+ act = 0;
+ }
+#line 127 "c/notation.rl"
+
+#line 151 "c/notation.c"
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+ if ( cs == 0 )
+ goto _out;
+_resume:
+ _acts = _bloopnotes_actions + _bloopnotes_from_state_actions[cs];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 ) {
+ switch ( *_acts++ ) {
+ case 8:
+#line 1 "c/notation.rl"
+ {ts = p;}
+ break;
+#line 172 "c/notation.c"
+ }
+ }
+
+ _keys = _bloopnotes_trans_keys + _bloopnotes_key_offsets[cs];
+ _trans = _bloopnotes_index_offsets[cs];
+
+ _klen = _bloopnotes_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _bloopnotes_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += ((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+_eof_trans:
+ cs = _bloopnotes_trans_targs[_trans];
+
+ if ( _bloopnotes_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _bloopnotes_actions + _bloopnotes_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+#line 42 "c/notation.rl"
+ {
+ len = ATOI(ts, p - ts);
+ }
+ break;
+ case 1:
+#line 46 "c/notation.rl"
+ {
+ oct = ATOI(p - 1, 1);
+ }
+ break;
+ case 2:
+#line 50 "c/notation.rl"
+ {
+ switch (tone) {
+ case 'a': case 'A':
+ if (mod == 'b') NOTE.tone = 'a';
+ else if (mod == '#') NOTE.tone = 'b';
+ else NOTE.tone = 'A';
+ break;
+ case 'b': case 'B':
+ if (mod == 'b') NOTE.tone = 'b';
+ else if (mod == '#') NOTE.tone = 'C';
+ else NOTE.tone = 'B';
+ break;
+ case 'c': case 'C':
+ if (mod == 'b') NOTE.tone = 'B';
+ else if (mod == '#') NOTE.tone = 'd';
+ else NOTE.tone = 'C';
+ break;
+ case 'd': case 'D':
+ if (mod == 'b') NOTE.tone = 'd';
+ else if (mod == '#') NOTE.tone = 'e';
+ else NOTE.tone = 'D';
+ break;
+ case 'e': case 'E':
+ if (mod == 'b') NOTE.tone = 'e';
+ else if (mod == '#') NOTE.tone = 'F';
+ else NOTE.tone = 'E';
+ break;
+ case 'f': case 'F':
+ if (mod == 'b') NOTE.tone = 'E';
+ else if (mod == '#') NOTE.tone = 'g';
+ else NOTE.tone = 'F';
+ break;
+ case 'g': case 'G':
+ if (mod == 'b') NOTE.tone = 'g';
+ else if (mod == '#') NOTE.tone = 'a';
+ else NOTE.tone = 'G';
+ break;
+ }
+ }
+ break;
+ case 3:
+#line 91 "c/notation.rl"
+ { len = 1; }
+ break;
+ case 4:
+#line 92 "c/notation.rl"
+ { len = 1; }
+ break;
+ case 5:
+#line 93 "c/notation.rl"
+ { mod = p[-1]; }
+ break;
+ case 6:
+#line 95 "c/notation.rl"
+ { tone = p[-1]; }
+ break;
+ case 9:
+#line 105 "c/notation.rl"
+ {te = p+1;}
+ break;
+ case 10:
+#line 98 "c/notation.rl"
+ {te = p;p--;{
+ NOTE.tone = 0;
+ NEXT();
+ }}
+ break;
+ case 11:
+#line 102 "c/notation.rl"
+ {te = p;p--;{ NEXT(); }}
+ break;
+ case 12:
+#line 103 "c/notation.rl"
+ {te = p;p--;{ oct++; len = 4; }}
+ break;
+ case 13:
+#line 104 "c/notation.rl"
+ {te = p;p--;{ oct--; len = 4; }}
+ break;
+#line 330 "c/notation.c"
+ }
+ }
+
+_again:
+ _acts = _bloopnotes_actions + _bloopnotes_to_state_actions[cs];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 ) {
+ switch ( *_acts++ ) {
+ case 7:
+#line 1 "c/notation.rl"
+ {ts = 0;}
+ break;
+#line 343 "c/notation.c"
+ }
+ }
+
+ if ( cs == 0 )
+ goto _out;
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ if ( p == eof )
+ {
+ if ( _bloopnotes_eof_trans[cs] > 0 ) {
+ _trans = _bloopnotes_eof_trans[cs] - 1;
+ goto _eof_trans;
+ }
+ }
+
+ _out: {}
+ }
+#line 128 "c/notation.rl"
+
+ return S;
+}
+
+bloopsatrack *
+bloops_track2(bloops *B, bloopsaphone *P, char *track)
+{
+ return bloops_track(B, P, track, strlen(track));
+}
+
+char *
+bloops_track_str(bloopsatrack *track)
+{
+ char *str = (char *)malloc(sizeof(char) * track->nlen * 6), *ptr = str;
+ int i, adv;
+
+ for (i = 0; i < track->nlen; i++)
+ {
+ if (ptr > str)
+ strcat(ptr++, " ");
+
+ if (track->notes[i].duration != 4)
+ {
+ adv = sprintf(ptr, "%d:", (int)track->notes[i].duration);
+ ptr += adv;
+ }
+
+ if (track->notes[i].tone)
+ {
+ char tone[3] = "\0\0\0";
+ tone[0] = track->notes[i].tone;
+ switch (tone[0]) {
+ case 'a': tone[0] = 'A'; tone[1] = 'b'; break;
+ case 'b': tone[0] = 'B'; tone[1] = 'b'; break;
+ case 'd': tone[0] = 'C'; tone[1] = '#'; break;
+ case 'e': tone[0] = 'E'; tone[1] = 'b'; break;
+ case 'g': tone[0] = 'F'; tone[1] = '#'; break;
+ }
+ adv = sprintf(ptr, "%s", tone);
+ ptr += adv;
+
+ adv = sprintf(ptr, "%d", (int)track->notes[i].octave);
+ ptr += adv;
+ }
+ }
+
+ return str;
+}
+
+float
+bloops_note_freq(char note, int octave)
+{
+ switch (note)
+ {
+ case 'A': // A
+ if (octave <= 0) return 0.0;
+ else if (octave == 1) return 0.121;
+ else if (octave == 2) return 0.175;
+ else if (octave == 3) return 0.248;
+ else if (octave == 4) return 0.353;
+ else if (octave == 5) return 0.500;
+ break;
+
+ case 'b': // A# or Bb
+ if (octave <= 0) return 0.0;
+ else if (octave == 1) return 0.125;
+ else if (octave == 2) return 0.181;
+ else if (octave == 3) return 0.255;
+ else if (octave == 4) return 0.364;
+ else if (octave == 5) return 0.515;
+ break;
+
+ case 'B': // B
+ if (octave <= 0) return 0.0;
+ else if (octave == 1) return 0.129;
+ else if (octave == 2) return 0.187;
+ else if (octave == 3) return 0.263;
+ else if (octave == 4) return 0.374;
+ else if (octave == 5) return 0.528;
+ break;
+
+ case 'C': // C
+ if (octave <= 1) return 0.0;
+ else if (octave == 2) return 0.133;
+ else if (octave == 3) return 0.192;
+ else if (octave == 4) return 0.271;
+ else if (octave == 5) return 0.385;
+ else if (octave == 6) return 0.544;
+ break;
+
+ case 'd': // C# or Db
+ if (octave <= 1) return 0.0;
+ else if (octave == 2) return 0.138;
+ else if (octave == 3) return 0.198;
+ else if (octave == 4) return 0.279;
+ else if (octave == 5) return 0.395;
+ else if (octave == 6) return 0.559;
+ break;
+
+ case 'D': // D
+ if (octave <= 1) return 0.0;
+ else if (octave == 2) return 0.143;
+ else if (octave == 3) return 0.202;
+ else if (octave == 4) return 0.287;
+ else if (octave == 5) return 0.406;
+ else if (octave == 6) return 0.575;
+ break;
+
+ case 'e': // D# or Eb
+ if (octave <= 1) return 0.0;
+ else if (octave == 2) return 0.148;
+ else if (octave == 3) return 0.208;
+ else if (octave == 4) return 0.296;
+ else if (octave == 5) return 0.418;
+ else if (octave == 6) return 0.593;
+ break;
+
+ case 'E': // E
+ if (octave <= 1) return 0.0;
+ else if (octave == 2) return 0.152;
+ else if (octave == 3) return 0.214;
+ else if (octave == 4) return 0.305;
+ else if (octave == 5) return 0.429;
+ else if (octave == 6) return 0.608;
+ break;
+
+ case 'F': // F
+ if (octave <= 1) return 0.0;
+ else if (octave == 2) return 0.155;
+ else if (octave == 3) return 0.220;
+ else if (octave == 4) return 0.314;
+ else if (octave == 5) return 0.441;
+ break;
+
+ case 'g': // F# or Gb
+ if (octave <= 1) return 0.0;
+ else if (octave == 2) return 0.160;
+ else if (octave == 3) return 0.227;
+ else if (octave == 4) return 0.323;
+ else if (octave == 5) return 0.454;
+ break;
+
+ case 'G': // G
+ if (octave <= 1) return 0.0;
+ else if (octave == 2) return 0.164;
+ else if (octave == 3) return 0.234;
+ else if (octave == 4) return 0.332;
+ else if (octave == 5) return 0.468;
+ break;
+
+ case 'a': // G# or Ab
+ if (octave <= 1) return 0.117;
+ else if (octave == 2) return 0.170;
+ else if (octave == 3) return 0.242;
+ else if (octave == 4) return 0.343;
+ else if (octave == 5) return 0.485;
+ break;
+ }
+
+ return 0.0;
+}
+
+#define KEY(name) key = (void *)&P->name
+
+
+#line 528 "c/notation.c"
+static const char _bloopserial_actions[] = {
+ 0, 1, 0, 1, 1, 1, 2, 1,
+ 5, 1, 6, 1, 7, 1, 8, 1,
+ 9, 1, 10, 1, 11, 1, 12, 1,
+ 13, 1, 14, 1, 15, 1, 16, 1,
+ 17, 1, 18, 1, 19, 1, 20, 1,
+ 21, 1, 22, 1, 23, 1, 24, 1,
+ 25, 1, 26, 1, 27, 1, 29, 1,
+ 30, 1, 31, 1, 32, 1, 33, 1,
+ 34, 1, 35, 1, 36, 2, 1, 3,
+ 2, 1, 35, 2, 4, 28, 3, 1,
+ 3, 35
+};
+
+static const unsigned char _bloopserial_key_offsets[] = {
+ 0, 0, 3, 4, 7, 13, 15, 18,
+ 20, 23, 25, 26, 27, 28, 29, 32,
+ 33, 34, 35, 36, 39, 41, 42, 43,
+ 44, 47, 48, 49, 50, 51, 54, 55,
+ 56, 57, 60, 62, 63, 66, 67, 68,
+ 69, 70, 73, 76, 77, 78, 79, 82,
+ 83, 86, 87, 88, 89, 90, 93, 96,
+ 97, 98, 99, 102, 103, 104, 105, 106,
+ 109, 110, 111, 112, 115, 116, 118, 119,
+ 120, 121, 124, 125, 126, 127, 128, 129,
+ 130, 133, 137, 138, 139, 140, 143, 144,
+ 145, 146, 147, 150, 151, 152, 153, 154,
+ 155, 158, 159, 160, 161, 164, 165, 166,
+ 167, 170, 175, 176, 177, 178, 179, 182,
+ 183, 184, 185, 186, 187, 188, 189, 190,
+ 191, 192, 193, 194, 198, 199, 200, 201,
+ 202, 205, 206, 207, 210, 211, 212, 213,
+ 214, 217, 218, 219, 220, 221, 224, 237,
+ 240, 245, 248
+};
+
+static const char _bloopserial_trans_keys[] = {
+ 114, 115, 116, 112, 32, 9, 13, 32,
+ 45, 9, 13, 48, 57, 48, 57, 46,
+ 48, 57, 48, 57, 46, 48, 57, 48,
+ 57, 112, 101, 101, 100, 32, 9, 13,
+ 116, 97, 99, 107, 32, 9, 13, 101,
+ 115, 99, 97, 121, 32, 9, 13, 108,
+ 105, 100, 101, 32, 9, 13, 114, 101,
+ 113, 32, 9, 13, 112, 115, 102, 32,
+ 9, 13, 119, 101, 101, 112, 32, 9,
+ 13, 105, 112, 115, 109, 105, 116, 32,
+ 9, 13, 102, 32, 9, 13, 119, 101,
+ 101, 112, 32, 9, 13, 104, 115, 117,
+ 97, 115, 101, 32, 9, 13, 119, 101,
+ 101, 112, 32, 9, 13, 110, 99, 104,
+ 32, 9, 13, 101, 112, 115, 101, 97,
+ 116, 32, 9, 13, 111, 110, 97, 110,
+ 99, 101, 32, 9, 13, 108, 113, 117,
+ 119, 105, 100, 101, 32, 9, 13, 117,
+ 97, 114, 101, 32, 9, 13, 115, 116,
+ 97, 105, 110, 32, 9, 13, 101, 101,
+ 112, 32, 9, 13, 121, 112, 101, 32,
+ 9, 13, 32, 110, 115, 9, 13, 111,