xiki 0.5.0a
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +11 -0
- data/LICENSE +22 -0
- data/README.markdown +83 -0
- data/Rakefile +8 -0
- data/bin/xiki +46 -0
- data/etc/command/xiki_command.rb +203 -0
- data/etc/command/xiki_process.rb +52 -0
- data/etc/command/xiki_wrapper +2 -0
- data/etc/js/menu1.js +55 -0
- data/etc/js/xiki.js +259 -0
- data/etc/logo.png +0 -0
- data/etc/presentations/bootstrap.deck +5 -0
- data/etc/presentations/databases.deck +41 -0
- data/etc/presentations/diffs.deck +23 -0
- data/etc/presentations/documentation.deck +14 -0
- data/etc/presentations/effects.deck +5 -0
- data/etc/presentations/face.deck +297 -0
- data/etc/presentations/files.deck +79 -0
- data/etc/presentations/icons.deck +22 -0
- data/etc/presentations/images.deck +24 -0
- data/etc/presentations/key_shortcuts.deck +16 -0
- data/etc/presentations/macros.deck +18 -0
- data/etc/presentations/menu_classes.deck +44 -0
- data/etc/presentations/menu_directories.deck +30 -0
- data/etc/presentations/notes.deck +19 -0
- data/etc/presentations/other_languages.deck +55 -0
- data/etc/presentations/other_wiki_syntaxes.deck +4 -0
- data/etc/presentations/piano.deck +5 -0
- data/etc/presentations/potential/diffs.deck +38 -0
- data/etc/presentations/potential/evolution.deck +18 -0
- data/etc/presentations/potential/intro.deck +711 -0
- data/etc/presentations/potential/intro1.deck +711 -0
- data/etc/presentations/potential/intro2.deck +97 -0
- data/etc/presentations/potential/make_mysql_menu.deck +36 -0
- data/etc/presentations/potential/ruby_development.deck +17 -0
- data/etc/presentations/potential/ui_prototyping.deck +50 -0
- data/etc/presentations/potential/web_dev.deck +4 -0
- data/etc/presentations/potential/web_development.deck +10 -0
- data/etc/presentations/potential/wiki.deck +45 -0
- data/etc/presentations/presentations.deck +24 -0
- data/etc/presentations/rails_development.deck +29 -0
- data/etc/presentations/search_key_shortcuts.deck +37 -0
- data/etc/presentations/simplest_possible_ui.deck +37 -0
- data/etc/presentations/svg.deck +5 -0
- data/etc/presentations/testing.deck +28 -0
- data/etc/presentations/the_end.deck +13 -0
- data/etc/presentations/type_something_and_double_click.deck +57 -0
- data/etc/presentations/type_the_acronym.deck +144 -0
- data/etc/presentations/web_browser.deck +56 -0
- data/etc/presentations/xiki_command.deck +20 -0
- data/etc/presentations/xiki_url.deck +14 -0
- data/etc/shark.icns +0 -0
- data/etc/shark_script.icns +0 -0
- data/etc/snippets/html.notes +7 -0
- data/etc/snippets/notes.notes +20 -0
- data/etc/snippets/rb.notes +38 -0
- data/etc/templates/menu_template.menu +2 -0
- data/etc/templates/menu_template.rb +8 -0
- data/etc/templates/template.rb +5 -0
- data/etc/themes/Dark_Metal.notes +28 -0
- data/etc/themes/Orange_Path.notes +15 -0
- data/etc/themes/Shiny_Blue.notes +27 -0
- data/etc/themes/Shiny_Green.notes +27 -0
- data/etc/wrappers/wrapper.js +17 -0
- data/etc/wrappers/wrapper.py +20 -0
- data/etc/wrappers/wrapper.rb +25 -0
- data/lib/block.rb +72 -0
- data/lib/bookmarks.rb +352 -0
- data/lib/buffers.rb +170 -0
- data/lib/clipboard.rb +333 -0
- data/lib/code.rb +860 -0
- data/lib/code_tree.rb +476 -0
- data/lib/color.rb +274 -0
- data/lib/console.rb +557 -0
- data/lib/control_lock.rb +9 -0
- data/lib/control_tab.rb +176 -0
- data/lib/core_ext.rb +31 -0
- data/lib/cursor.rb +111 -0
- data/lib/deletes.rb +65 -0
- data/lib/diff_log.rb +297 -0
- data/lib/effects.rb +145 -0
- data/lib/environment.rb +5 -0
- data/lib/file_tree.rb +1875 -0
- data/lib/files.rb +334 -0
- data/lib/hide.rb +259 -0
- data/lib/history.rb +286 -0
- data/lib/image.rb +51 -0
- data/lib/incrementer.rb +15 -0
- data/lib/insert.rb +7 -0
- data/lib/irc.rb +22 -0
- data/lib/key_bindings.rb +658 -0
- data/lib/keys.rb +754 -0
- data/lib/launcher.rb +1351 -0
- data/lib/line.rb +429 -0
- data/lib/links.rb +6 -0
- data/lib/location.rb +175 -0
- data/lib/macros.rb +48 -0
- data/lib/man.rb +19 -0
- data/lib/menu.rb +708 -0
- data/lib/merb.rb +259 -0
- data/lib/message.rb +5 -0
- data/lib/meths.rb +56 -0
- data/lib/mode.rb +34 -0
- data/lib/move.rb +248 -0
- data/lib/notes.rb +1000 -0
- data/lib/numbers.rb +45 -0
- data/lib/ol.rb +203 -0
- data/lib/ol_helper.rb +44 -0
- data/lib/overlay.rb +167 -0
- data/lib/pause_means_space.rb +68 -0
- data/lib/php.rb +22 -0
- data/lib/projects.rb +21 -0
- data/lib/relinquish_exception.rb +2 -0
- data/lib/remote.rb +206 -0
- data/lib/requirer.rb +46 -0
- data/lib/rest_tree.rb +108 -0
- data/lib/ruby.rb +57 -0
- data/lib/ruby_console.rb +165 -0
- data/lib/search.rb +1572 -0
- data/lib/search_term.rb +40 -0
- data/lib/snippet.rb +68 -0
- data/lib/specs.rb +229 -0
- data/lib/styles.rb +274 -0
- data/lib/svn.rb +682 -0
- data/lib/text_util.rb +110 -0
- data/lib/tree.rb +1871 -0
- data/lib/tree_cursor.rb +87 -0
- data/lib/trouble_shooting.rb +27 -0
- data/lib/url_tree.rb +11 -0
- data/lib/view.rb +1474 -0
- data/lib/window.rb +133 -0
- data/lib/xiki.rb +404 -0
- data/menus/accounts.rb +5 -0
- data/menus/address_book.rb +21 -0
- data/menus/agenda.rb +28 -0
- data/menus/all.rb +5 -0
- data/menus/amazon.rb +16 -0
- data/menus/app.rb +16 -0
- data/menus/applescript.rb +46 -0
- data/menus/as.rb +15 -0
- data/menus/bookmarklet.rb +63 -0
- data/menus/bootstrap.rb +568 -0
- data/menus/browse.rb +13 -0
- data/menus/browser.rb +78 -0
- data/menus/cassandra_db.rb +36 -0
- data/menus/chmod.rb +27 -0
- data/menus/classes.rb +5 -0
- data/menus/coffee_script.rb +35 -0
- data/menus/computer.rb +24 -0
- data/menus/contacts.rb +5 -0
- data/menus/cookies.rb +25 -0
- data/menus/couch.rb +184 -0
- data/menus/crop.rb +45 -0
- data/menus/css.rb +55 -0
- data/menus/current.rb +5 -0
- data/menus/db.rb +12 -0
- data/menus/deck.rb +219 -0
- data/menus/dictionary.rb +9 -0
- data/menus/dir.rb +8 -0
- data/menus/disk.rb +5 -0
- data/menus/do.rb +13 -0
- data/menus/docs.rb +58 -0
- data/menus/dotsies.rb +107 -0
- data/menus/edited.rb +18 -0
- data/menus/emacs.rb +17 -0
- data/menus/enter.rb +13 -0
- data/menus/eval.rb +17 -0
- data/menus/executable.rb +16 -0
- data/menus/filter.rb +46 -0
- data/menus/firefox.rb +607 -0
- data/menus/foo.rb +30 -0
- data/menus/french.rb +7 -0
- data/menus/git.rb +185 -0
- data/menus/gito.rb +785 -0
- data/menus/google.rb +35 -0
- data/menus/google_images.rb +11 -0
- data/menus/google_patents.rb +10 -0
- data/menus/gutenberg.rb +13 -0
- data/menus/head.rb +10 -0
- data/menus/headings.rb +39 -0
- data/menus/html.rb +61 -0
- data/menus/icon.rb +40 -0
- data/menus/images.menu +2 -0
- data/menus/img.rb +15 -0
- data/menus/info.rb +9 -0
- data/menus/ip.rb +10 -0
- data/menus/iterm.rb +36 -0
- data/menus/itunes.rb +78 -0
- data/menus/javascript.rb +74 -0
- data/menus/layout.rb +18 -0
- data/menus/local_storage.rb +67 -0
- data/menus/ls.rb +19 -0
- data/menus/mac.rb +87 -0
- data/menus/maps.rb +18 -0
- data/menus/matches.rb +18 -0
- data/menus/memcache.rb +117 -0
- data/menus/mkdir.rb +23 -0
- data/menus/mongo.rb +83 -0
- data/menus/mysql.rb +294 -0
- data/menus/node.rb +88 -0
- data/menus/open.rb +19 -0
- data/menus/outline.rb +24 -0
- data/menus/piano.rb +746 -0
- data/menus/postgres.rb +34 -0
- data/menus/pre.rb +5 -0
- data/menus/python.rb +39 -0
- data/menus/rails.rb +160 -0
- data/menus/rake.rb +12 -0
- data/menus/redmine.rb +168 -0
- data/menus/riak_tree.rb +204 -0
- data/menus/rss.rb +15 -0
- data/menus/safari.rb +11 -0
- data/menus/sass.rb +15 -0
- data/menus/say.rb +6 -0
- data/menus/scale.rb +49 -0
- data/menus/serve.rb +78 -0
- data/menus/shuffle.rb +24 -0
- data/menus/spanish.rb +7 -0
- data/menus/standalone.rb +57 -0
- data/menus/tail.rb +41 -0
- data/menus/technologies.rb +19 -0
- data/menus/themes.rb +32 -0
- data/menus/thesaurus.rb +13 -0
- data/menus/to.rb +24 -0
- data/menus/twitter.rb +57 -0
- data/menus/wikipedia.rb +34 -0
- data/menus/words.rb +11 -0
- data/spec/code_tree_spec.rb +59 -0
- data/spec/diff_log_spec.rb +40 -0
- data/spec/file_tree_spec.rb +102 -0
- data/spec/keys_spec.rb +24 -0
- data/spec/line_spec.rb +68 -0
- data/spec/menu_spec.rb +50 -0
- data/spec/ol_spec.rb +98 -0
- data/spec/remote_spec.rb +43 -0
- data/spec/search_spec.rb +162 -0
- data/spec/text_util_spec.rb +119 -0
- data/spec/tree_cursor_spec.rb +91 -0
- data/spec/tree_spec.rb +955 -0
- data/tests/console_test.rb +11 -0
- data/tests/couch_db_test.rb +12 -0
- data/tests/diff_log_test.rb +43 -0
- data/tests/el_mixin.rb +16 -0
- data/tests/git_test.rb +95 -0
- data/tests/keys_test.rb +19 -0
- data/tests/line_test.rb +38 -0
- data/tests/merb_test.rb +11 -0
- data/tests/redmine_test.rb +50 -0
- data/tests/remote_test.rb +31 -0
- data/tests/rest_tree_test.rb +70 -0
- data/xiki.gemspec +37 -0
- metadata +332 -0
data/menus/mysql.rb
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
class Mysql
|
2
|
+
def self.menu
|
3
|
+
"
|
4
|
+
- @tables/
|
5
|
+
- @dbs/
|
6
|
+
- @columns/
|
7
|
+
- .setup/
|
8
|
+
- .start/
|
9
|
+
- .start in background/
|
10
|
+
- stop/
|
11
|
+
@ $ ps -eo pcpu,pid,user,args | grep mysql | grep -v grep
|
12
|
+
@ $ kill _
|
13
|
+
- db/
|
14
|
+
- .use/
|
15
|
+
- .create/
|
16
|
+
- .drop/
|
17
|
+
- table/
|
18
|
+
- .create/
|
19
|
+
- .drop/
|
20
|
+
- .install/
|
21
|
+
- config/
|
22
|
+
> Main config file
|
23
|
+
@ /etc/my.cnf
|
24
|
+
|
25
|
+
> Example config files
|
26
|
+
@ /usr/local/Cellar/mysql/5.5.25/support-files/
|
27
|
+
- **cnf/
|
28
|
+
- misc commands/
|
29
|
+
> Drop db
|
30
|
+
@ % mysqladmin -u root drop foo
|
31
|
+
|
|
32
|
+
> Others
|
33
|
+
@ technologies/mysql/
|
34
|
+
> Or just type some sql here
|
35
|
+
| show tables
|
36
|
+
"
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.install
|
40
|
+
"
|
41
|
+
> Installing Mysql
|
42
|
+
For now, this just has the mac / homebrew instructions. Fork xiki on github to add docs for other platforms.
|
43
|
+
|
44
|
+
> Install using homebrew
|
45
|
+
- 1. double-click to install) @ % brew install mysql
|
46
|
+
- 2. look at the output) and run the commands it tells you to run
|
47
|
+
|
48
|
+
> More
|
49
|
+
See this link for more info on installing:
|
50
|
+
@http://www.mysql.com/downloads/mysql/
|
51
|
+
"
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.menu_after txt, *args
|
55
|
+
return nil if txt
|
56
|
+
ENV['no_slash'] = "1"
|
57
|
+
Tree.quote self.run(nil, ENV['txt'])
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.default_db db
|
61
|
+
@default_db = db
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.start
|
65
|
+
Console.run "mysqld", :buffer=>"mysql", :dir=>"/tmp/"
|
66
|
+
View.to_buffer "mysql"
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.start_in_background
|
71
|
+
Console.run "mysql.server start"
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.tables *args
|
75
|
+
if ! @default_db && ! args[0]
|
76
|
+
@default_db = "dev" # Temp
|
77
|
+
end
|
78
|
+
|
79
|
+
self.dbs @default_db, *args
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.dbs db=nil, table=nil, row=nil
|
83
|
+
|
84
|
+
# If nothing passed, list db's
|
85
|
+
|
86
|
+
if db.nil?
|
87
|
+
txt = Mysql.run('', 'show databases')
|
88
|
+
return txt.split[1..-1].map{|o| "#{o}/"}
|
89
|
+
end
|
90
|
+
|
91
|
+
db.sub! /\/$/, '' if db
|
92
|
+
table.sub! /\/$/, '' if table
|
93
|
+
|
94
|
+
# If just db passed, list the tables
|
95
|
+
|
96
|
+
if table.nil?
|
97
|
+
txt = Mysql.run(db, 'show tables')
|
98
|
+
if txt.blank?
|
99
|
+
@default_db = db
|
100
|
+
return "> No tables exist. Create one?\n- @mysql/setup/table/create/"
|
101
|
+
end
|
102
|
+
return txt.split[1..-1].map{|o| "#{o}/"}
|
103
|
+
end
|
104
|
+
|
105
|
+
# If table passed, so show all records
|
106
|
+
|
107
|
+
if row.nil?
|
108
|
+
# Whole table
|
109
|
+
|
110
|
+
if ! $el || ! Keys.prefix_u
|
111
|
+
sql = "select * from #{table} limit 1000"
|
112
|
+
out = self.run(db, sql)
|
113
|
+
out = "No records, create one?\n#{self.dummy_row(db, table)}" if out.blank?
|
114
|
+
return Tree.quote out #.gsub(/^/, '| ')
|
115
|
+
else
|
116
|
+
# Pick out just a few fields
|
117
|
+
fields = self.run db, "select * from #{table} limit 1"
|
118
|
+
fields = fields.sub(/\n.+/m, '').split("\t")
|
119
|
+
fields &= ['id', 'slug', 'name', 'partner_id']
|
120
|
+
fields = ['*'] if fields.blank?
|
121
|
+
sql = "select #{fields.join ', '} from #{table} limit 1000"
|
122
|
+
txt = Mysql.run(db, sql)
|
123
|
+
|
124
|
+
return txt.gsub(/^/, '| ')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Row passed, so save
|
129
|
+
|
130
|
+
self.save db, table, row
|
131
|
+
|
132
|
+
".flash - saved record!"
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.dummy_row db=nil, table=nil
|
136
|
+
fields = self.fields db, table
|
137
|
+
examples = {
|
138
|
+
"int"=>"1",
|
139
|
+
"varchar"=>"foo",
|
140
|
+
"text"=>"bar bar",
|
141
|
+
"date"=>"2011-01-01",
|
142
|
+
"time"=>"2011-01-01",
|
143
|
+
}
|
144
|
+
fields = fields.map{|o| examples[o[1]]}
|
145
|
+
fields.join("\t")
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.fields db, table=nil
|
149
|
+
txt = self.run db, "desc #{table}"
|
150
|
+
txt.sub(/^.+\n/, '').split("\n").map{|o|
|
151
|
+
l = o.split("\t")
|
152
|
+
[l[0], l[1].sub(/\(.+/, '')] }
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.use kind=nil, db=nil
|
156
|
+
# If nothing passed, show db's
|
157
|
+
|
158
|
+
if db.nil?
|
159
|
+
return Mysql.dbs
|
160
|
+
end
|
161
|
+
|
162
|
+
@default_db = db
|
163
|
+
".flash - using db #{db}!"
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.create what, name=nil, columns=nil
|
167
|
+
if name.nil?
|
168
|
+
View.prompt "Type a name"
|
169
|
+
return nil
|
170
|
+
end
|
171
|
+
|
172
|
+
if what == "db"
|
173
|
+
txt = Console.run "mysqladmin -u root create #{name}", :sync=>true
|
174
|
+
return ".flash - created db!"
|
175
|
+
end
|
176
|
+
|
177
|
+
if columns.nil?
|
178
|
+
return "
|
179
|
+
| id int not null auto_increment primary key,
|
180
|
+
| name VARCHAR(20),
|
181
|
+
| details text,
|
182
|
+
| datestamp DATE,
|
183
|
+
| timestamp TIME,
|
184
|
+
"
|
185
|
+
end
|
186
|
+
|
187
|
+
txt = "
|
188
|
+
CREATE TABLE #{name} (
|
189
|
+
#{ENV['txt'].strip.sub(/,\z/, '')}
|
190
|
+
);
|
191
|
+
"
|
192
|
+
|
193
|
+
out = self.run(@default_db, txt)
|
194
|
+
|
195
|
+
".flash - created table!"
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.drop what, name=nil
|
199
|
+
if name.nil?
|
200
|
+
return what == "db" ? Mysql.dbs : Mysql.tables
|
201
|
+
end
|
202
|
+
|
203
|
+
if what == "db"
|
204
|
+
txt = Console.run "mysqladmin -u root drop #{name}" #, :sync=>true
|
205
|
+
return
|
206
|
+
end
|
207
|
+
|
208
|
+
out = self.run(@default_db, "drop table #{name}")
|
209
|
+
|
210
|
+
".flash - dropped table!"
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.run db, sql
|
214
|
+
db ||= @default_db
|
215
|
+
|
216
|
+
File.open("/tmp/tmp.sql", "w") { |f| f << sql }
|
217
|
+
out = Console.run "mysql -u root #{db} < /tmp/tmp.sql", :sync=>true
|
218
|
+
|
219
|
+
raise "> Mysql doesn't appear to be running. Start it?\n- @mysql/setup/start/" if out =~ /^ERROR.+Can't connect/
|
220
|
+
raise "| Select a db first:\n- @mysql/setup/db/use/" if out =~ /^ERROR.+: No database selected/
|
221
|
+
raise "| Database doesn't exist. Create it?\n- @mysql/setup/db/create/#{$1}/" if out =~ /^ERROR.+Unknown database '(.+)'/
|
222
|
+
raise "| Table doesn't exist. Create it?\n- @mysql/setup/table/create/#{$1}/" if out =~ /^ERROR.+Table '.+\.(.+)' doesn't exist/
|
223
|
+
raise Tree.quote(out) if out =~ /^ERROR/
|
224
|
+
out
|
225
|
+
end
|
226
|
+
|
227
|
+
def self.save db, table, row
|
228
|
+
fields = self.fields db, table
|
229
|
+
row = row.sub(/^\| /, '').split("\t")
|
230
|
+
txt = fields.map{|o| o[0]}.map_with_index{|o, i| "#{o}='#{row[i]}'"}.join(", ")
|
231
|
+
self.run db, "INSERT INTO #{table} SET #{txt} ON DUPLICATE KEY UPDATE #{txt}"
|
232
|
+
end
|
233
|
+
|
234
|
+
def self.select statement, row=nil
|
235
|
+
table = statement[/from (.+?)( |$)/, 1]
|
236
|
+
|
237
|
+
# If just statement, run it
|
238
|
+
|
239
|
+
if row.nil?
|
240
|
+
txt = Mysql.run nil, statement.sub(/\/$/, '')
|
241
|
+
txt = "No records, create one?\n#{self.dummy_row(@default_db, table)}" if txt.blank?
|
242
|
+
return Tree.quote txt
|
243
|
+
end
|
244
|
+
|
245
|
+
# Row passed, so save it
|
246
|
+
|
247
|
+
ENV['no_slash'] = "1"
|
248
|
+
self.save @default_db, table, row
|
249
|
+
|
250
|
+
".flash - saved!"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
Keys.enter_list_mysql { Launcher.insert('- Mysql.dbs/') }
|
255
|
+
|
256
|
+
Launcher.add /^select \* from($|\/)/ do |path|
|
257
|
+
if path !~ /\// # If just "select * from", show all tables
|
258
|
+
next Tree.<< Mysql.run(@default_db, 'show tables'), :no_slash=>1
|
259
|
+
end
|
260
|
+
|
261
|
+
# If listed table underneath, collapse to same line
|
262
|
+
CodeTree.kill_siblings
|
263
|
+
Move.backward
|
264
|
+
Deletes.backward
|
265
|
+
Deletes.backward
|
266
|
+
Move.to_end
|
267
|
+
|
268
|
+
end
|
269
|
+
|
270
|
+
Launcher.add(/^select /) do |path|
|
271
|
+
args = Menu.split(path)
|
272
|
+
Tree.<< Mysql.select(*args), :no_slash=>(args.length > 1)
|
273
|
+
end
|
274
|
+
|
275
|
+
Launcher.add "tables" do |path|
|
276
|
+
Mysql.tables *Menu.split(path, :rootless=>1)
|
277
|
+
end
|
278
|
+
|
279
|
+
Launcher.add "dbs" do |path|
|
280
|
+
Mysql.dbs *Menu.split(path, :rootless=>1)
|
281
|
+
end
|
282
|
+
|
283
|
+
Launcher.add "rows" do |path|
|
284
|
+
args = path.split('/')[1..-1]
|
285
|
+
Mysql.tables(*args)
|
286
|
+
end
|
287
|
+
|
288
|
+
Launcher.add "columns" do |path|
|
289
|
+
args = path.split('/')[1..-1]
|
290
|
+
if args.size > 0
|
291
|
+
next Mysql.run(@default_db, "desc #{args[0]}").gsub!(/^/, '| ')
|
292
|
+
end
|
293
|
+
Mysql.tables(*args)
|
294
|
+
end
|
data/menus/node.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
class Node
|
2
|
+
def self.menu
|
3
|
+
"
|
4
|
+
> Pass javascript to eval in node
|
5
|
+
| puts(1 + 2)
|
6
|
+
- .controller/
|
7
|
+
- docs/
|
8
|
+
- menu/
|
9
|
+
> To try out controller code
|
10
|
+
| @node/controller/
|
11
|
+
| | function
|
12
|
+
|
13
|
+
- node/
|
14
|
+
> Snippets
|
15
|
+
@technologies/node_js/
|
16
|
+
"
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.menu_after output, *args
|
20
|
+
return output if output
|
21
|
+
|
22
|
+
if args.empty?
|
23
|
+
View.prompt("Enter some code to run in node.js")
|
24
|
+
return "| "
|
25
|
+
end
|
26
|
+
|
27
|
+
return self.block if args == ['block']
|
28
|
+
|
29
|
+
txt = Tree.leaf args[0]
|
30
|
+
result = Tree.quote self.run(txt)
|
31
|
+
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.wrap_controller code
|
36
|
+
|
37
|
+
"
|
38
|
+
var http = require('http');
|
39
|
+
http.createServer(function (req, res) {
|
40
|
+
|
41
|
+
#{code}
|
42
|
+
}).listen(8161, '127.0.0.1');
|
43
|
+
console.log('Server running at http://127.0.0.1:8161/');
|
44
|
+
".unindent
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.controller *args
|
49
|
+
|
50
|
+
return "
|
51
|
+
| // Sample controller code
|
52
|
+
| console.log('got a request');
|
53
|
+
| res.end('Hello World');
|
54
|
+
" if args.empty?
|
55
|
+
|
56
|
+
code = self.wrap_controller ENV['txt']
|
57
|
+
self.run_controller code
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.run_controller code
|
61
|
+
File.open("/tmp/controller.js", "w") { |f| f << code }
|
62
|
+
|
63
|
+
Buffers.delete "node" if View.buffer_open? "node"
|
64
|
+
|
65
|
+
Console.run "node controller.js", :dir=>"/tmp/", :buffer=>"node"
|
66
|
+
$el.sit_for 0.2
|
67
|
+
Firefox.url "http://localhost:8161"
|
68
|
+
".flash - showing in browser!"
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.block
|
72
|
+
left = Line.right + 1
|
73
|
+
ignore, ignore, right = View.block_positions "^>"
|
74
|
+
|
75
|
+
txt = self.run View.txt(right, left)
|
76
|
+
Block >> txt
|
77
|
+
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.run txt
|
82
|
+
file = "/tmp/nodejs.js"
|
83
|
+
txt = "function puts (txt){ return console.log(txt) }\n\n#{txt}"
|
84
|
+
File.open(file, "w") { |f| f << txt }
|
85
|
+
Console["node #{file}"]
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
data/menus/open.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class Open
|
2
|
+
def self.menu
|
3
|
+
%`
|
4
|
+
> Summary
|
5
|
+
| Keys shortcuts that start with "to+" (ctrl-t) such as to+end.
|
6
|
+
|
|
7
|
+
- frequent/
|
8
|
+
> Jumping cursor around
|
9
|
+
| open+bookmark: jump to a file
|
10
|
+
| open+tree: view a tree of a directory
|
11
|
+
| open+current: shows currently open files
|
12
|
+
| open+edited: shows recently edited files
|
13
|
+
| open+menu: opens view that lets you type a menu (type "-" to see all)
|
14
|
+
|
|
15
|
+
- others/
|
16
|
+
| open+history: shows recently viewed files
|
17
|
+
`
|
18
|
+
end
|
19
|
+
end
|
data/menus/outline.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
class Outline
|
2
|
+
def self.menu *target
|
3
|
+
|
4
|
+
if target.blank? # If just filter, show results
|
5
|
+
return View.txt.grep(/^> /).select{|o| o !~ /^> ?$/}.join("").gsub(/^/, '| ')
|
6
|
+
end
|
7
|
+
# Navigated to target text
|
8
|
+
|
9
|
+
# Grab line manually, because input will have all lines grouped together
|
10
|
+
# Should there be an option to have just 1 line passed in?
|
11
|
+
# How would it work?
|
12
|
+
# Something in the routing?
|
13
|
+
target = Line.value
|
14
|
+
target.sub! /^ *\| /, ''
|
15
|
+
|
16
|
+
View.to_highest
|
17
|
+
result = Search.forward "^#{target}$"
|
18
|
+
|
19
|
+
View.recenter_top
|
20
|
+
Line.to_beginning
|
21
|
+
nil
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
data/menus/piano.rb
ADDED
@@ -0,0 +1,746 @@
|
|
1
|
+
Requirer.require_gem 'midiator', :optional=>1
|
2
|
+
|
3
|
+
require "mode"
|
4
|
+
|
5
|
+
class Piano
|
6
|
+
|
7
|
+
include MIDIator::Notes rescue nil
|
8
|
+
include MIDIator::Drums rescue nil
|
9
|
+
|
10
|
+
@@midi = nil
|
11
|
+
@@velocity = 126
|
12
|
+
@@tempo = 120
|
13
|
+
@@probability = 100
|
14
|
+
@@melodic = 0
|
15
|
+
@@melodic_accumulator = []
|
16
|
+
@@climb = 0
|
17
|
+
@@pentatonic = false
|
18
|
+
@@variation = 0
|
19
|
+
@@consistency = 0
|
20
|
+
@@mode = 0
|
21
|
+
@@octave = 0
|
22
|
+
@@program = 1
|
23
|
+
@@repeat = 1
|
24
|
+
@@names = ['Acoustic Grand Piano', 'Bright Acoustic Piano', 'Electric Grand Piano', 'Honky-tonk Piano', 'Electric Piano 1', 'Electric Piano 2', 'Harpsichord', 'Clavinet', 'Celesta', 'Glockenspiel', 'Music Box', 'Vibraphone', 'Marimba', 'Xylophone', 'Tubular Bells', 'Dulcimer', 'Drawbar Organ', 'Percussive Organ', 'Rock Organ', 'Church Organ', 'Reed Organ', 'Accordion', 'Harmonica', 'Tango Accordion', 'Acoustic Guitar (nylon)', 'Acoustic Guitar (steel)', 'Electric Guitar (jazz)', 'Electric Guitar (clean)', 'Electric Guitar (muted)', 'Overdriven Guitar', 'Distortion Guitar', 'Guitar harmonics', 'Acoustic Bass', 'Electric Bass (finger)', 'Electric Bass (pick)', 'Fretless Bass', 'Slap Bass 1', 'Slap Bass 2', 'Synth Bass 1', 'Synth Bass 2', 'Violin', 'Viola', 'Cello', 'Contrabass', 'Tremolo Strings', 'Pizzicato Strings', 'Orchestral Harp', 'Timpani', 'String Ensemble 1', 'String Ensemble 2', 'Synth Strings 1', 'Synth Strings 2', 'Choir Aahs', 'Voice Oohs', 'Synth Choir', 'Orchestra Hit', 'Trumpet', 'Trombone', 'Tuba', 'Muted Trumpet', 'French Horn', 'Brass Section', 'Synth Brass 1', 'Synth Brass 2', 'Soprano Sax', 'Alto Sax', 'Tenor Sax', 'Baritone Sax', 'Oboe', 'English Horn', 'Bassoon', 'Clarinet', 'Piccolo', 'Flute', 'Recorder', 'Pan Flute', 'Blown Bottle', 'Shakuhachi', 'Whistle', 'Ocarina', 'Lead 1 (square)', 'Lead 2 (sawtooth)', 'Lead 3 (calliope)', 'Lead 4 (chiff)', 'Lead 5 (charang)', 'Lead 6 (voice)', 'Lead 7 (fifths)', 'Lead 8 (bass + lead)', 'Pad 1 (new age)', 'Pad 2 (warm)', 'Pad 3 (polysynth)', 'Pad 4 (choir)', 'Pad 5 (bowed)', 'Pad 6 (metallic)', 'Pad 7 (halo)', 'Pad 8 (sweep)', 'FX 1 (rain)', 'FX 2 (soundtrack)', 'FX 3 (crystal)', 'FX 4 (atmosphere)', 'FX 5 (brightness)', 'FX 6 (goblins)', 'FX 7 (echoes)', 'FX 8 (sci-fi)', 'Sitar', 'Banjo', 'Shamisen', 'Koto', 'Kalimba', 'Bag pipe', 'Fiddle', 'Shanai', 'Tinkle Bell', 'Agogo', 'Steel Drums', 'Woodblock', 'Taiko Drum', 'Melodic Tom', 'Synth Drum', 'Reverse Cymbal', 'Guitar Fret Noise', 'Breath Noise', 'Seashore', 'Bird Tweet', 'Telephone Ring', 'Helicopter', 'Applause', 'Gunshot']
|
25
|
+
|
26
|
+
begin
|
27
|
+
@@map = {
|
28
|
+
'@'=>BassDrum2, '#'=>BassDrum1,
|
29
|
+
'='=>SnareDrum2, '-'=>SnareDrum1,
|
30
|
+
"'"=>ClosedHiHat, '"'=>OpenHiHat,
|
31
|
+
'^'=>RideCymbal1, '`'=>CrashCymbal1, '*'=>CrashCymbal2, '<'=>Cowbell,
|
32
|
+
'['=>MidTom1, '_'=>MidTom2, ']'=>LowTom2,
|
33
|
+
}
|
34
|
+
rescue Exception=>e
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.menu
|
38
|
+
|
39
|
+
%`
|
40
|
+
> Pass in notes
|
41
|
+
| g cdefg c c
|
42
|
+
- .setup/
|
43
|
+
- .instrument/
|
44
|
+
- most common/
|
45
|
+
- Acoustic Grand Piano/
|
46
|
+
- Electric Piano 1/
|
47
|
+
- Glockenspiel/
|
48
|
+
- Vibraphone/
|
49
|
+
- Xylophone/
|
50
|
+
- Drawbar Organ/
|
51
|
+
- Church Organ/
|
52
|
+
- Accordion/
|
53
|
+
- Acoustic Guitar (nylon)/
|
54
|
+
- Distortion Guitar/
|
55
|
+
- Electric Bass (finger)/
|
56
|
+
- Violin/
|
57
|
+
- Tremolo Strings/
|
58
|
+
- Pizzicato Strings/
|
59
|
+
- Orchestral Harp/
|
60
|
+
- Timpani/
|
61
|
+
- String Ensemble 2/
|
62
|
+
- Synth Strings 2/
|
63
|
+
- Choir Aahs/
|
64
|
+
- Synth Choir/
|
65
|
+
- Orchestra Hit/
|
66
|
+
- Trumpet/
|
67
|
+
- Flute/
|
68
|
+
- Pan Flute/
|
69
|
+
- Lead 1 (square)/
|
70
|
+
- Lead 2 (sawtooth)/
|
71
|
+
- Pad 1 (new age)/
|
72
|
+
- Pad 2 (warm)/
|
73
|
+
- Pad 4 (choir)/
|
74
|
+
- Pad 7 (halo)/
|
75
|
+
- Pad 8 (sweep)/
|
76
|
+
- FX 3 (crystal)/
|
77
|
+
- FX 6 (goblins)/
|
78
|
+
- Steel Drums/
|
79
|
+
- Woodblock/
|
80
|
+
- Taiko Drum/
|
81
|
+
- all/
|
82
|
+
- .tempo/
|
83
|
+
- 60
|
84
|
+
- 120
|
85
|
+
- 240
|
86
|
+
- 480
|
87
|
+
- 960
|
88
|
+
- .repeat/
|
89
|
+
- 1
|
90
|
+
- 2
|
91
|
+
- 4
|
92
|
+
- 8
|
93
|
+
- .mode/
|
94
|
+
- lydian) 4
|
95
|
+
- ionian - major) 3
|
96
|
+
- mixolydian) 2
|
97
|
+
- dorian) 1
|
98
|
+
- aeolian - minor) 0
|
99
|
+
- phrygian) -1
|
100
|
+
- locrian) -2
|
101
|
+
- random/
|
102
|
+
- .pentatonic/
|
103
|
+
- off
|
104
|
+
- on
|
105
|
+
- .octave/
|
106
|
+
- 2
|
107
|
+
- 1
|
108
|
+
- 0
|
109
|
+
- -1
|
110
|
+
- -2
|
111
|
+
- .velocity/
|
112
|
+
- 126
|
113
|
+
- 96
|
114
|
+
- 64
|
115
|
+
- 32
|
116
|
+
- .variation/
|
117
|
+
- 0
|
118
|
+
- 1
|
119
|
+
- 2
|
120
|
+
- 3
|
121
|
+
- .consistency/
|
122
|
+
- 0%
|
123
|
+
- 25%
|
124
|
+
- 50%
|
125
|
+
- 75%
|
126
|
+
- .melodic/
|
127
|
+
- 1
|
128
|
+
- 0
|
129
|
+
- .climb/
|
130
|
+
- 1
|
131
|
+
- -1
|
132
|
+
- 0
|
133
|
+
- .probability/
|
134
|
+
- 100%
|
135
|
+
- 75%
|
136
|
+
- 50%
|
137
|
+
- .reset/
|
138
|
+
- .random notes/
|
139
|
+
- examples/
|
140
|
+
- basics/
|
141
|
+
- chords/
|
142
|
+
@piano/
|
143
|
+
| A A A B A
|
144
|
+
| C C D D C
|
145
|
+
| E F F F E
|
146
|
+
- two parts/
|
147
|
+
@piano/
|
148
|
+
| CGcCGc C GaCGa CGcCGc C GaCGa
|
149
|
+
| cde edc d c c de e
|
150
|
+
- three parts/
|
151
|
+
@piano/
|
152
|
+
| ABCDEFGabcdefghijklmnopqrstuv
|
153
|
+
| B C D E F G a b c d e f g h
|
154
|
+
| B C D E F G a
|
155
|
+
- sharps/
|
156
|
+
@piano/
|
157
|
+
| # # # # #
|
158
|
+
| ce ecbca Gb baGbG G G a
|
159
|
+
| #
|
160
|
+
| C E C A C L B E B N B L H
|
161
|
+
- drums/
|
162
|
+
@piano/
|
163
|
+
| ' ' ' ' ' '* '
|
164
|
+
| =@@= @@@=@@= @@@
|
165
|
+
- unofficial xiki theme song/
|
166
|
+
@piano/
|
167
|
+
| xiki is so great
|
168
|
+
| P Q P Q P Q P Q P Q P Q P Q P Q
|
169
|
+
| < < < < < < < < < < < < < < < <
|
170
|
+
| @ = @@= @ = @@= @ = @@= @ = @@=
|
171
|
+
- generation/
|
172
|
+
- variation/
|
173
|
+
@piano/
|
174
|
+
| reset()
|
175
|
+
| variation()
|
176
|
+
| aaaaaaaa
|
177
|
+
- probability/
|
178
|
+
@piano/
|
179
|
+
| reset()
|
180
|
+
| variation()
|
181
|
+
| probability(50)
|
182
|
+
| aaaaaaaaaaaa
|
183
|
+
- melodic/
|
184
|
+
@piano/
|
185
|
+
| reset()
|
186
|
+
| variation(1)
|
187
|
+
| melodic()
|
188
|
+
| aaaaaaaaaaaa
|
189
|
+
- climb/
|
190
|
+
@piano/
|
191
|
+
| reset()
|
192
|
+
| variation(1)
|
193
|
+
| melodic()
|
194
|
+
| climb()
|
195
|
+
| aaaaaaaaaaaa
|
196
|
+
- consistency/
|
197
|
+
@piano/
|
198
|
+
| reset()
|
199
|
+
| variation()
|
200
|
+
| consistency(80)
|
201
|
+
| aaaaaaaaaaaa
|
202
|
+
- solo/
|
203
|
+
@piano/
|
204
|
+
| reset()
|
205
|
+
| repeat(8)
|
206
|
+
| tempo(55)
|
207
|
+
| mode(rand 100)
|
208
|
+
| variation()
|
209
|
+
| consistency(50)
|
210
|
+
| melodic()
|
211
|
+
| probability(80)
|
212
|
+
| abcdefgh
|
213
|
+
- duet/
|
214
|
+
@piano/
|
215
|
+
| reset()
|
216
|
+
| repeat(8)
|
217
|
+
| tempo(35)
|
218
|
+
| mode(rand 8)
|
219
|
+
| variation(2)
|
220
|
+
| consistency(10)
|
221
|
+
| melodic()
|
222
|
+
| A A A A
|
223
|
+
| h h h h
|
224
|
+
- all together/
|
225
|
+
@piano/
|
226
|
+
| reset()
|
227
|
+
| repeat(8)
|
228
|
+
| tempo(45)
|
229
|
+
| mode(rand 100)
|
230
|
+
| variation()
|
231
|
+
| consistency(50)
|
232
|
+
| melodic()
|
233
|
+
| probability(80)
|
234
|
+
| aaaaaaaa
|
235
|
+
| AAAAAAAA
|
236
|
+
| H H
|
237
|
+
- everything random/
|
238
|
+
@piano/
|
239
|
+
| reset()
|
240
|
+
| repeat(16)
|
241
|
+
| tempo(rand(60) + 40)
|
242
|
+
| mode(rand 200)
|
243
|
+
| variation(rand(6) + 1)
|
244
|
+
| consistency(rand(50))
|
245
|
+
| melodic(rand 1)
|
246
|
+
| octave(-1)
|
247
|
+
| probability(rand(55) + 45)
|
248
|
+
| aaaaaaaaaaaaaaaa
|
249
|
+
| AAAAAAAAAAAAAAAA
|
250
|
+
| H H H H
|
251
|
+
- cool instruments/
|
252
|
+
@piano/
|
253
|
+
| reset()
|
254
|
+
| repeat(32)
|
255
|
+
| tempo(rand(60) + 40)
|
256
|
+
| mode(rand 200)
|
257
|
+
| variation(rand(6) + 1)
|
258
|
+
| instrument([112, 108, 107, 102, 101, 100, 98, 97, 96, 95, 89, 88, 87, 86, 80, 54, 50, 49, 46, 45, 34, 12, 11, 10, 9, 8, 4][rand 27])
|
259
|
+
| consistency(rand(50))
|
260
|
+
| melodic(rand 1)
|
261
|
+
| octave(-1)
|
262
|
+
| probability(rand(55) + 45)
|
263
|
+
| aaaaaaaaaaaaaaaa
|
264
|
+
| AAAAAAAAAAAAAAAA
|
265
|
+
| H H H H
|
266
|
+
- .api/
|
267
|
+
| Play some notes
|
268
|
+
@ Piano.song "abc"
|
269
|
+
- .docs/
|
270
|
+
> Single notes
|
271
|
+
- @piano/a/
|
272
|
+
- @piano/55/
|
273
|
+
|
274
|
+
> Multiple notes
|
275
|
+
- @piano/cde edc d c c de e
|
276
|
+
- @piano/some words for fun
|
277
|
+
|
278
|
+
> Modes
|
279
|
+
modes/
|
280
|
+
| For reference, here are the whole and half steps for the options under
|
281
|
+
| the "mode" menu. By default the A scale is used.
|
282
|
+
|
|
283
|
+
| - O o o oo o oO: lydian
|
284
|
+
| - O o oo o o oO: ionian (major)
|
285
|
+
| - O o oo o oo O: mixolydian
|
286
|
+
| - O oo o o oo O: dorian
|
287
|
+
| - O oo o oo o O: aeolian (minor)
|
288
|
+
| - Oo o o oo o O: phrygian
|
289
|
+
| - Oo o oo o o O: locrian
|
290
|
+
`
|
291
|
+
end
|
292
|
+
|
293
|
+
def self.names
|
294
|
+
@@names
|
295
|
+
end
|
296
|
+
|
297
|
+
|
298
|
+
def self.menu_after menu_output, *args
|
299
|
+
|
300
|
+
# Don't interfere if menu did something
|
301
|
+
return menu_output if menu_output
|
302
|
+
|
303
|
+
# If just number, intercept
|
304
|
+
if args.length == 1 && args[0] =~ /^\d+$/
|
305
|
+
self.note args[0].to_i
|
306
|
+
return false
|
307
|
+
end
|
308
|
+
|
309
|
+
if $el
|
310
|
+
if Line =~ /\(/
|
311
|
+
Tree.to_parent
|
312
|
+
Move.to_end
|
313
|
+
Search.forward("^[^(\n]+$")
|
314
|
+
end
|
315
|
+
txt = ENV['txt']
|
316
|
+
else
|
317
|
+
txt = args[0]
|
318
|
+
end
|
319
|
+
|
320
|
+
self.song txt, :move=>1
|
321
|
+
|
322
|
+
nil
|
323
|
+
end
|
324
|
+
|
325
|
+
def self.song txt, options={}
|
326
|
+
@@lines = txt.split("\n")#.reverse
|
327
|
+
|
328
|
+
self.extract_functions
|
329
|
+
|
330
|
+
# If only config, just run first ones
|
331
|
+
# if @@lines.empty?
|
332
|
+
# return self.run_functions @@functions_by_index[0], :include_all
|
333
|
+
# end
|
334
|
+
self.run_functions @@functions_by_index[0], :include_all
|
335
|
+
|
336
|
+
repeat = (@@functions_by_index[0]||[]).find{|o| o =~ /^rep(eat)?\(/}
|
337
|
+
@@repeat = (repeat[/\d+/]||"4").to_i if repeat
|
338
|
+
|
339
|
+
@@repeat.times do |i|
|
340
|
+
|
341
|
+
# Start at where cursor is
|
342
|
+
if $el
|
343
|
+
View.column = Line.value[/.+(\/|\| ?)/].length if options[:move]
|
344
|
+
end
|
345
|
+
|
346
|
+
longest = @@lines.inject(0){|acc, e| e.length > acc ? e.length : acc}
|
347
|
+
|
348
|
+
longest.times do |j|
|
349
|
+
# self.run_functions @@functions_by_index[j] # unless j == 0
|
350
|
+
self.run_functions @@functions_by_index[j] unless i == 0
|
351
|
+
|
352
|
+
sharp = false
|
353
|
+
@@lines.each_with_index do |line, track|
|
354
|
+
char = line[j] ? line[j].chr : nil
|
355
|
+
self.note char, :no_sit=>1, :sharp=>sharp, :track=>track
|
356
|
+
sharp = char == "#"
|
357
|
+
end
|
358
|
+
if $el
|
359
|
+
Move.forward if options[:move] && View.cursor != Line.right
|
360
|
+
end
|
361
|
+
self.pause
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
nil
|
366
|
+
end
|
367
|
+
|
368
|
+
def self.run_functions list, include_all=nil
|
369
|
+
@@in_run_functions = true
|
370
|
+
(list||[]).each do |item|
|
371
|
+
next if !include_all && item =~ /^rep(eat)?\(/
|
372
|
+
eval("Piano.#{item}")
|
373
|
+
end
|
374
|
+
@@in_run_functions = false
|
375
|
+
end
|
376
|
+
|
377
|
+
def self.extract_functions
|
378
|
+
lines, @@lines = @@lines.partition{|i| i =~ /\(/}
|
379
|
+
|
380
|
+
@@functions_by_index = {}
|
381
|
+
lines.each do |line|
|
382
|
+
Code.parse_functions line, @@functions_by_index
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
def self.clear channel=1
|
387
|
+
self.driver.control_change 123, channel, 123
|
388
|
+
end
|
389
|
+
|
390
|
+
def self.<< letter
|
391
|
+
self.note letter
|
392
|
+
end
|
393
|
+
|
394
|
+
def self.letter_to_number letter, options={}
|
395
|
+
|
396
|
+
adjustment =@@mode
|
397
|
+
|
398
|
+
letter.next! if @@pentatonic && (letter == "b" || letter == "e")
|
399
|
+
|
400
|
+
number = letter[0].to_i
|
401
|
+
number = case letter
|
402
|
+
when "a".."z"; number - 96
|
403
|
+
when "A".."G"; number - 71
|
404
|
+
when "H".."N"; number - 85
|
405
|
+
when "O".."U"; number - 99
|
406
|
+
when "V".."Z"; number - 111
|
407
|
+
else; raise "Don't know how to convert the note #{letter} to a number."
|
408
|
+
end
|
409
|
+
|
410
|
+
number = self.apply_variation number, options
|
411
|
+
|
412
|
+
number = number * 12/7.0
|
413
|
+
number -= 0.01
|
414
|
+
adjustment -= 2
|
415
|
+
adjustment = (adjustment / 7.0) - 0.01
|
416
|
+
number += adjustment
|
417
|
+
|
418
|
+
number = number.floor
|
419
|
+
number += 68
|
420
|
+
number
|
421
|
+
end
|
422
|
+
|
423
|
+
def self.apply_variation number, options={}
|
424
|
+
return number if rand(100) > (100 - @@consistency) # Do nothing if consistency says to stop
|
425
|
+
|
426
|
+
random = rand(@@variation+1)
|
427
|
+
|
428
|
+
if @@climb == 0
|
429
|
+
random *= ((-1) ** rand(2)) # Half of the time, make it decrease note
|
430
|
+
end
|
431
|
+
# Ol << "random: #{random.inspect}"
|
432
|
+
|
433
|
+
if @@melodic == 1
|
434
|
+
track = options[:track]
|
435
|
+
@@melodic_accumulator[track] ||= 0
|
436
|
+
random *= @@climb if @@climb != 0
|
437
|
+
@@melodic_accumulator[track] += random
|
438
|
+
|
439
|
+
@@melodic_accumulator[track] = 0 if @@melodic_accumulator[track] > 28 || @@melodic_accumulator[track] < -28
|
440
|
+
|
441
|
+
random = @@melodic_accumulator[track]
|
442
|
+
end
|
443
|
+
|
444
|
+
number + random
|
445
|
+
end
|
446
|
+
|
447
|
+
def self.apply_probability number
|
448
|
+
return 0 if rand(100) > @@probability
|
449
|
+
number
|
450
|
+
end
|
451
|
+
|
452
|
+
|
453
|
+
def self.note letter='a', options={}
|
454
|
+
|
455
|
+
return if letter.nil? || letter == "#"
|
456
|
+
|
457
|
+
channel = 1
|
458
|
+
velocity = @@velocity
|
459
|
+
|
460
|
+
# Varying the velocity doesn't sound super-great
|
461
|
+
# velocity = 63 + rand(63)
|
462
|
+
|
463
|
+
if letter.is_a? Fixnum
|
464
|
+
number = letter
|
465
|
+
# If super-low, make them audible
|
466
|
+
number += 69 if number <= 20
|
467
|
+
elsif letter =~ /^[0-9]$/
|
468
|
+
number = letter[0] + 21
|
469
|
+
elsif letter =~ /^[a-zA-Z]$/
|
470
|
+
number = self.letter_to_number letter, options
|
471
|
+
number = self.apply_probability number
|
472
|
+
elsif letter.length == 1 && letter.count("@#='\"`^*<[_]-") == 1
|
473
|
+
channel = 10
|
474
|
+
number = @@map[letter]
|
475
|
+
velocity = letter.count("@#=-") == 1 ? 126 : 65
|
476
|
+
elsif letter == " " || letter == "+"
|
477
|
+
number = 0
|
478
|
+
elsif letter.is_a?(String) && letter.length > 1
|
479
|
+
letter.split('').each{|o| self.note o}
|
480
|
+
return
|
481
|
+
else
|
482
|
+
raise "- Note #{letter.inspect} not recognized!"
|
483
|
+
end
|
484
|
+
return if number == 0
|
485
|
+
|
486
|
+
number += 1 if options[:sharp]
|
487
|
+
number += (@@octave * 12)
|
488
|
+
|
489
|
+
self.driver.note_on(number, channel, velocity) unless number == 0
|
490
|
+
|
491
|
+
return if options[:no_sit]
|
492
|
+
|
493
|
+
self.pause
|
494
|
+
nil
|
495
|
+
end
|
496
|
+
|
497
|
+
def self.pause
|
498
|
+
pause = @@tempo * 4
|
499
|
+
pause = pause / 60.0
|
500
|
+
pause = 1 / pause
|
501
|
+
$el ? $el.sit_for(pause) : sleep(pause)
|
502
|
+
Piano.clear
|
503
|
+
Piano.clear 10
|
504
|
+
end
|
505
|
+
|
506
|
+
def self.keydef letter, note, channel=1, velocity=126
|
507
|
+
$el.define_key(:piano_mode_map, letter) do
|
508
|
+
self.driver.note_on(note, channel, velocity)
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
def self.midi
|
513
|
+
@@midi || self.connect
|
514
|
+
end
|
515
|
+
|
516
|
+
def self.keys
|
517
|
+
$el.elvar.piano_mode_map = $el.make_sparse_keymap unless $el.boundp :piano_mode_map
|
518
|
+
|
519
|
+
keydef " ", BassDrum2, 10
|
520
|
+
keydef "-", SnareDrum2, 10
|
521
|
+
keydef "1", SnareDrum1, 10
|
522
|
+
|
523
|
+
keydef "6", ClosedHiHat, 10, 60
|
524
|
+
keydef "1", OpenHiHat, 10, 60
|
525
|
+
keydef $el.kbd("C-i"), RideCymbal1, 10, 60
|
526
|
+
|
527
|
+
# Note: keys are optimized for dvorak
|
528
|
+
keydef ";", C3; keydef "o", Cs3
|
529
|
+
keydef "q", D3; keydef "e", Ds3
|
530
|
+
keydef "j", E3
|
531
|
+
|
532
|
+
keydef "k", F3; keydef "i", Fs3
|
533
|
+
keydef "x", G3; keydef "d", Gs3
|
534
|
+
keydef "b", A3; keydef "h", As3
|
535
|
+
keydef "m", B3
|
536
|
+
keydef "w", C4; keydef "n", Cs4
|
537
|
+
keydef "v", D4; keydef "s", Ds4
|
538
|
+
keydef "z", E4
|
539
|
+
|
540
|
+
keydef "'", B3; keydef "3", Cs4
|
541
|
+
keydef ",", C4; keydef "3", Cs4
|
542
|
+
keydef ".", D4; keydef "4", Ds4
|
543
|
+
keydef "p", E4
|
544
|
+
keydef "y", F4; keydef "6", Fs4
|
545
|
+
keydef "f", G4; keydef "7", Gs4
|
546
|
+
keydef "g", A4; keydef "8", As4
|
547
|
+
keydef "c", B4
|
548
|
+
keydef "r", C5; keydef "0", Cs5
|
549
|
+
keydef "l", D5; keydef "[", Ds5
|
550
|
+
keydef "/", E5
|
551
|
+
keydef "=", F5
|
552
|
+
keydef '\\\\', G5
|
553
|
+
|
554
|
+
"aut259]".split(//).each do |letter|
|
555
|
+
$el.define_key(:piano_mode_map, letter) do
|
556
|
+
View.message("key '#{letter}' inactive")
|
557
|
+
end
|
558
|
+
|
559
|
+
end
|
560
|
+
|
561
|
+
keydef "", :nothing # nothing
|
562
|
+
|
563
|
+
|
564
|
+
$el.define_key(:piano_mode_map, $el.kbd("<right>")) do
|
565
|
+
@@program += 1
|
566
|
+
View.message "program: #{@@program+1} - #{@@names[@@program]}"
|
567
|
+
@@midi.program_change 1, @@program
|
568
|
+
end
|
569
|
+
|
570
|
+
$el.define_key(:piano_mode_map, $el.kbd("<left>")) do
|
571
|
+
@@program -= 1
|
572
|
+
View.message "program: #{@@program+1} - #{@@names[@@program]}"
|
573
|
+
@@midi.program_change 1, @@program
|
574
|
+
end
|
575
|
+
|
576
|
+
$el.define_key(:piano_mode_map, $el.kbd("<backspace>")) do
|
577
|
+
@@midi.control_change 123, 1, 123
|
578
|
+
end
|
579
|
+
|
580
|
+
rescue Exception=>e
|
581
|
+
|
582
|
+
end
|
583
|
+
|
584
|
+
def self.init
|
585
|
+
self.keys
|
586
|
+
# Make piano mode happen for .piano files
|
587
|
+
Mode.define(:piano, ".piano") do
|
588
|
+
Notes.apply_styles
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
def self.instrument type, name=nil, options={}
|
593
|
+
# If 'all' show all
|
594
|
+
return @@names.map{|o| "- #{o}/"}.join("\n") if type == 'all' && name.nil?
|
595
|
+
|
596
|
+
# If 1 arg, assume it's the name
|
597
|
+
name = type if name.nil?
|
598
|
+
|
599
|
+
|
600
|
+
if name.is_a?(Fixnum)
|
601
|
+
index = name
|
602
|
+
else
|
603
|
+
name = Regexp.escape name
|
604
|
+
name.gsub! '\ ', ".+"
|
605
|
+
index = @@names.index{|o| o =~ /^#{name}$/i}
|
606
|
+
index ||= @@names.index{|o| o =~ /^#{name}/i}
|
607
|
+
index ||= @@names.index{|o| o =~ /#{name}/i}
|
608
|
+
end
|
609
|
+
|
610
|
+
@@midi.program_change 1, (index||0)
|
611
|
+
return if options[:quiet]
|
612
|
+
|
613
|
+
# TODO: turn back on, but not when called from .run_functions
|
614
|
+
# How to detect?
|
615
|
+
# or, maybe just set instance variable when in .run_functions
|
616
|
+
# @@in_run_functions = true
|
617
|
+
# maybe .sub! it to have an extra parameter to suppress?
|
618
|
+
# instrument('Piano') -> instrument('Piano', :suppress)
|
619
|
+
Piano.note "abc" unless @@in_run_functions
|
620
|
+
end
|
621
|
+
|
622
|
+
def self.reset
|
623
|
+
self.connect
|
624
|
+
|
625
|
+
@@velocity = 126
|
626
|
+
@@tempo = 120
|
627
|
+
@@probability = 100
|
628
|
+
|
629
|
+
@@variation = 0
|
630
|
+
@@melodic = 0
|
631
|
+
@@melodic_accumulator = []
|
632
|
+
@@climb = 0
|
633
|
+
@@pentatonic = false
|
634
|
+
@@consistency = 0
|
635
|
+
@@mode = 0
|
636
|
+
@@octave = 0
|
637
|
+
@@program = 1
|
638
|
+
@@repeat = 1
|
639
|
+
@@seed = nil
|
640
|
+
|
641
|
+
".flash - success!"
|
642
|
+
end
|
643
|
+
|
644
|
+
#
|
645
|
+
# Low level call to configure midi.
|
646
|
+
#
|
647
|
+
def self.control_change a, b, c
|
648
|
+
self.driver.control_change a, b, c
|
649
|
+
end
|
650
|
+
|
651
|
+
def self.connect
|
652
|
+
@@midi = MIDIator::Interface.new
|
653
|
+
@@midi.use :dls_synth
|
654
|
+
# This doesn't work in Lion :(
|
655
|
+
@@midi.control_change 32, 10, 1 # Drums: R-808 is Program 26 in LSB bank 1
|
656
|
+
@@midi.control_change 7, 1, 126 # Turn volume up to max
|
657
|
+
@@midi
|
658
|
+
end
|
659
|
+
|
660
|
+
def self.velocity txt="126"; @@velocity = txt.to_i; ".flash - updated!"; end
|
661
|
+
def self.tempo txt="120"; @@tempo = txt.to_i; ".flash - updated!"; end
|
662
|
+
def self.probability txt="50"; @@probability = txt.to_s.sub('%', '').to_i; ".flash - updated!"; end
|
663
|
+
def self.variation txt="2"
|
664
|
+
@@variation = txt.to_i
|
665
|
+
if @@seed # If seed set manually, just use it
|
666
|
+
seed = @@seed
|
667
|
+
else # Else auto-generate seed
|
668
|
+
seed = rand 999_999_999_999_999_999_999
|
669
|
+
end
|
670
|
+
|
671
|
+
srand seed
|
672
|
+
|
673
|
+
".flash - updated!"
|
674
|
+
end
|
675
|
+
def self.melodic txt="1"; @@melodic = txt.to_i; ".flash - updated!"; end
|
676
|
+
def self.climb txt="1"; @@climb = txt.to_i; ".flash - updated!"; end
|
677
|
+
def self.pentatonic txt="1"; Ol.<<(txt); @@pentatonic = [true, "on", 1].member?(txt); ".flash - updated!"; end
|
678
|
+
def self.consistency txt="50"; @@consistency = txt.to_s.sub('%', '').to_i; ".flash - updated!"; end
|
679
|
+
def self.octave txt="0"; @@octave = txt.to_i; ".flash - updated!"; end
|
680
|
+
def self.repeat txt="4"; @@repeat = txt.to_i; ".flash - updated!"; end
|
681
|
+
def self.seed txt; @@seed = txt.to_i; ".flash - updated!"; end
|
682
|
+
|
683
|
+
def self.mode txt=nil
|
684
|
+
return @@mode if txt.nil?
|
685
|
+
|
686
|
+
if txt.to_s == "random"
|
687
|
+
random = (-2..9).to_a[rand 7]
|
688
|
+
@@mode = random
|
689
|
+
return ".flash - updated to #{random}!"
|
690
|
+
end
|
691
|
+
|
692
|
+
@@mode = txt.to_i
|
693
|
+
".flash - updated!"
|
694
|
+
end
|
695
|
+
|
696
|
+
class << self
|
697
|
+
alias :tem :tempo
|
698
|
+
alias :pro :probability
|
699
|
+
alias :mel :melodic
|
700
|
+
alias :cli :climb
|
701
|
+
alias :vel :velocity
|
702
|
+
alias :pen :pentatonic
|
703
|
+
alias :res :reset
|
704
|
+
alias :rep :repeat
|
705
|
+
alias :var :variation
|
706
|
+
alias :con :consistency
|
707
|
+
alias :oct :octave
|
708
|
+
alias :mod :mode
|
709
|
+
alias :ins :instrument
|
710
|
+
end
|
711
|
+
|
712
|
+
def self.driver
|
713
|
+
@@midi ||= self.connect
|
714
|
+
end
|
715
|
+
|
716
|
+
def self.random_notes range=nil, notes=nil
|
717
|
+
if range.nil?
|
718
|
+
return "- a..g/"
|
719
|
+
end
|
720
|
+
|
721
|
+
# If just range, generate
|
722
|
+
|
723
|
+
if notes.nil?
|
724
|
+
|
725
|
+
range ||= "a..g"
|
726
|
+
|
727
|
+
range =~ /(.+)\.\.(.+)/
|
728
|
+
range = $1..$2
|
729
|
+
|
730
|
+
range = range.to_a
|
731
|
+
|
732
|
+
txt = ""
|
733
|
+
8.times do
|
734
|
+
txt << range[rand range.length]
|
735
|
+
end
|
736
|
+
return "| #{txt}"
|
737
|
+
end
|
738
|
+
|
739
|
+
self.song ENV['txt']
|
740
|
+
nil
|
741
|
+
end
|
742
|
+
|
743
|
+
end
|
744
|
+
|
745
|
+
Piano.init # Define mode
|
746
|
+
Menu.drums :menu=>'piano'
|