One of the new features in the Preview Release is the software MIDI
synthesizer. The Midi Kit contains three classes for controlling the MIDI
synthesizer: BSynth
, BMidiSynth
,
and BMidiSynthFile
. The BSynth
object is
the interface to the underlying synthesizer engine. BMidiSynth
is a
subclass of BMidi that forwards MIDI events to the BSynth
object. And
BMidiSynthFile
is a specialization of
BMidiSynth
which reads from a
standard MIDI file.
An application that uses the MIDI synthesizer starts by creating a BSynth
object. Currently you can only create one BSynth
object per application,
but you probably only need one anyway. After creating the BSynth
, call
LoadSynthData
(B_BIG_SYNTH
)
on it. This tells the BSynth
to use the
instrument file
/boot/beos/etc/synth/big_synth.sy
.
If the call to LoadSynthData()
fails, it probably couldn't find the
instrument file. LoadSynthData()
does not load the instruments into
memory yet. Unless you are playing directly from a MIDI file you will
still need to load the instruments.
The application then creates a BMidiSynth
object which you can send MIDI
events to just as you would to any other BMidi
object. After creating the
BMidiSynth
, call EnableInput()
on it. The first argument to EnableInput()
should be true, and the second argument indicates whether to pre-load all
instruments from the instrument file.
The easiest way to see how this works is to try it. Here is a program
that plays six notes on a piano. Don't forget to link with
libmidi.so
.
#include <MidiSynth.h>main
() {BSynth
synth
; status_terr
=synth
.LoadSynthData
(B_BIG_SYNTH
); if (err
) {printf
("LoadSynthData: %x\n",err
); return -1; }BMidiSynth
song
;err
=song
.EnableInput
(true
,false
); if (err
) {printf
("EnableInput: %x\n",err
); return -1; } intchannel
= 1; // MIDI channel number intinstrument
=B_ACOUSTIC_GRAND
; // GM instrumentsong
.LoadInstrument
(instrument
);song
.ProgramChange
(channel
,instrument
); for (inti
= 0;i
< 6;i
++) {song
.NoteOn
(channel
, 60 + 5 *i
, 127);snooze
(250000); }snooze
(2000000);song
.AllNotesOff
(FALSE
); return 0; }
In this example channel
is a MIDI channel number (1-16), and
instrument
is a General MIDI instrument number. The instrument numbers
are represented by the midi_axe constants defined in
MidiDefs.h
. The
ProgramChange()
call associates an instrument with a channel.
You can also play the synthesizer from an external MIDI keyboard. If you
are on a Mac you will also need a Mac MIDI interface (I'm using an
"Opcode Midi Translator II"). To do this, you just connect a BMidiPort
to
the BMidiSynth
:
BSynth
synth
;synth
.LoadSynthData
(B_BIG_SYNTH
);BMidiSynth
song
;printf
("Loading instruments...\n");song
.EnableInput
(true
,true
);printf
("Done.\n");BMidiPort
port
; status_terr
=port
.Open
("midi2"); // printer port on Macs if (err
)printf
("Open: %x\n",err
);port
.Connect
(&song
);port
.Start
();
In this case the second argument to EnableInput()
is true
. So all the
instruments will be pre-loaded, which may take a few seconds. Note that
on Macs, "midi1" is the modem port and "midi2" is the printer port.
To play a MIDI file, use a BMidiSynthFile
instead of a BMidiSynth
:
#include <MidiSynthFile.h>main
() {BSynth
synth
;synth
.LoadSynthData
(B_BIG_SYNTH
); char*filename
= "/boot/optional/midi/BeBoxBeBop.mid";BMidiSynthFile
song
; entry_refref
;get_ref_for_path
(filename
, &ref
); status_terr
=song
.LoadFile
(&ref
); if (err
) {printf
("LoadFile: can't open %s\n",filename
); return -1; }song
.Start
(); while (!song
.IsFinished
())snooze
(1000000);song
.Fade
(); return 0; }
There are also several other BSynth
methods
such as SetReverb()
and
SetSynthVolume()
to experiment with, but this is enough to get started
using the BSynth
. So dig out those old MIDI keyboards and plug them in!
Inspiration comes wheeling around the corner like a '68 Chevy Camero: screaming rubber, hoodless, with a caved-in passenger door. Greek blue and pumped to evade, or catch, or surprise.
Effort squeezes into a tiny hallway, sweaty and breathing hard. Then comes the split, the lesson, the book, the movie and you wanna know the rest...
Buy the rights.
How bizarre.
I spent 35 minutes waiting for my friend's 9500/132 to upgrade itself from 7.5.something to 7.6. Then Corel's word processor would lock up whenever she tried to save a document. Neat.
So she called Corel and they told her it was $25 for help.
Neat.
Tonight she told me that it turned out to be a problem with Extensions. Imagine that. A problem with Extensions. You could almost write a recent-history book called...
"A Problem with Extensions"
And you could write it with StyledEdit, and you could look up the words you don't know how to spell with NetPositive targeted to autoload your favorite online dictionary. You could even e-mail the final manuscript to your publisher, click back and check your bank account to make sure they don't stiff you on the five cents a word you're paid to describe the very disappointing behaviour of one careless twit behind that big fruity curtain.
Because baby you had it all along.
BeOS CDs are breeding like AOL floppies.
She asked if the BeOS would save her, and I said, "Yes." It's simple, really.
She's a student. She wants e-mail, a word processor, and Internet access.
She doesn't want a million upgrade headaches.
She doesn't need all those fancy legacy applications.
She's got nice hardware.
Calgon, take me away.
PR2 is almost ready.
It fixes most of what you were asking for.
Oh and those of you who have been submitting PPP bugs, please remember to tell us what kind of modem you have and if possible, what kind of modem you are connecting to.
So blah blah blah Power Computing and Apple, and blah blah blah CHRP and BURP (Be United Reference Platform.) Blah blah blah Moto and does it really matter anyway? Latitude is coming. Chill out for a couple months. Then it's gonna get VERY interesting. You saw the demo.
I'll see a thousand BIntel machines clog my cube before Xmas, and by Spring you'd be a fool not to be running multi-boot on your 95% of the back seat.
If you kids don't stop fighting I'll turn this IPO around right now!
And speaking of super-duper, if anyone out there at Radius is reading this, then we've got a couple of bugs with those kool expensive cards you sell. Achieve greater market penetration, contribute to the Be Hardware Fund. Pack up your dreams of compatibility and ship them to:
Baron Arnold
800 El Camino Real, Suite 300
Menlo Park, CA 94025.
Oh and props out to the people who built the Be Machine.
I use it as my main testing box.
It's fast and blue. =)
I love the overspray on the CD drawer the most.
Very kool.
But seriously, about the Be Hardware Fund, if you are somehow in charge of something where what you make is something you'd like to see BeCompatible, send me one please?
And for those of you just tuning in, the Intel world is just so chock full of hardware options, send me stuff. Really. You know the song. We'll try support it, but only if we can test it.
Speaking of testing, I wanna publicly thank Jake Hambey. He's filed a million good bugs and helped me take a few very big steps into scripting the testing grunt work by porting Expect. If you ever wanted to script a telnet session then get Expect from BeWare.
Wow. Thanks, Jake.
And ya know?
He plays a mean ocarina. =)
Driving up to the Avenues the other night, I was telling Jake that it's really the people at Be who have allowed us to develop at such a rapid rate. It has been the inter-linking of so many different personalities, of so many different work styles: so many concessions and acknowledgments made in the name of The Right Way. It's quite simple, and yet, terrifically effective. We joked with abstraction about the BeActionPlaySet, plastic StarWars-size BePlay figures of Dominic, and Benoit, and George. And we considered, with respect, how many more of each individual engineer Be would need to cover perfectly the near-future work to be done. As for testing, I think just one each of Ming and Mel and Jake and I could handle it. Well, maybe two Mings. One for each wing. =) We'll definitely need more space though.
And so the fourth floor acquisition is but one release away (gotta put those engineers somewhere). MIA and CBS and DVD and I'm a little worried that we will grow too fast. That there will be so much to do that we won't have time to find out who our co-workers are. What they love and dislike. What they have seen. Where they have been. Hmmm. Perhaps this is an attempt to jinx us. Keep the lid on our secret a little longer. Let this GUI simmer in these, the last of our simple days.
There are so many things we'd like to give you.
We talk about them every day.
At lunch, at dinner, on the weekends.
We want to give you everything.
So blah blah blah MacWorld and Comdex.
Blah blah blah shop talk shop talk shop talk.
Watch for BeShred in a shrink wrap near you.
Get your ticket now for "The Power of the Word NO."
Hang on to your sense of humor and consider please
that 150%, is just a sleepier 110.
Spin a few times, but never forever.
Try to be humble and honest and clever.
Love = work + your life and your friends so Valerie,
here's where my article ends.
Are you AllAttached? When you're using a programming framework, sometimes
it takes a while to figure out all the ins and outs of what happens when.
The BeOS programming interface is clean and simple to use, but learning a
little bit about proper usage can go a long way. I was recently playing
with a library of code which was largely unknown to me, when my
application kept crashing on initialization. It turns out that I was
trying to set a target handler for a object that didn't quite exist yet.
Specifically it was a button in one of the views that is not created
until the AttachedToWindow()
method is called.
Well, AttachedToWindow()
gets called when you actually add a view to a
window's hierarchy. At this point, you can call the Window()
method of a
view to get a pointer to the window you're attached to. Also, at this
point none of your child view's AttachedToWindow()
methods will have been
called, and you know nothing about your sibling views. So what's safe to
do here? Things that are directly related to your view that you didn't
already do in your constructor. You might add child views, set your font
and colors and all that.
What about AllAttached()
? You want to use this when it is absolutely
paramount that all of your child views have been attached. This would be
the case if you are going to perform an action that depends on the
existence of your child views in the hierarchy.
So let's say there should be a button in your view with the name "OK". And you want to set the target handler of that button to be yourself. Ideally you want to do the following:
BButton
*aButton
= (BButton
*)FindView
("OK"); if (0 !=aButton
)aButton
->SetTarget
(this
);
Where is it safe to put this code? Well, if you were the view writer and
you know explicitly when the button was created, then you can do it
anywhere you want. If you are sub-classing some other view, then it's
safest to stick the code in the AllAttached()
method, assuming that the
original view author created the button in their AttachedToWindow()
method.
This is what I did, and my bugs went away. Just goes to show you...
Then I got to figuring, there's got to be more uses of BMessageFilter
s.
So I sought to simplify the HelloWorld application. Often times when you
create a simple little app, you might create a sub-class of BApplication
and BWindow
, simply to implement the
BWindow
::QuitRequested()
method so
when the window closes, the app will quit. Well, that seems like a bit
much just to quit an app, how about a filter?
#include <MessageFilter.h> #include <Application.h> #include <Window.h> static filter_resultQuitFilter
(BMessage
*msg
,BHandler
**target
,BMessageFilter
*filter
) {be_app
->PostMessage
(B_QUIT_REQUESTED
); returnB_SKIP_MESSAGE
; }
In this case, whenever this filter receives a message, it will post a
message to the application object asking it to quit. You could have
actually checked the *msg
passed in to make sure what type of message it
is, but in this very simple case we don't care. As you will see below,
the filter is installed in such a way that only one type of message will
come to this filter in the first place.
So, now my simple application to pop a window up on the screen and quit when it's closed looks like this:
BRect
gWindowSize
=BRect
(100,80,260,120); classHelloView
: publicBView
{ public:HelloView
(BRect
frame
, char *name
); virtual voidDraw
(BRect
updateRect
); };HelloView
::HelloView
(BRect
rect
, char *name
) :BView
(rect
,name
,B_FOLLOW_ALL
,B_WILL_DRAW
) { } voidHelloView
::Draw
(BRect
) {SetFont
(be_bold_font
);SetFontSize
(24);MovePenTo
(BPoint
(10, 30));DrawString
("Hello, World!"); }main
() { // Start off with an instance of an application objectBApplication
*myApplication
= newBApplication
('HLWD'); // Setup our windowBWindow
*aWindow
= newBWindow
(gWindowSize
, "Hello",B_TITLED_WINDOW
,B_NOT_RESIZABLE
); // Create a filter that will only look at B_QUIT_REQUESTED // message. These are sent to the window whenever the // close box is clicked on, or when you do an Alt-Q.BMessageFilter
*filter
= newBMessageFilter
(B_QUIT_REQUESTED
,QuitFilter
);aWindow
->AddCommonFilter
(filter
); // view rect should be same size as window rect but with // left top at (0, 0)gWindowSize
.OffsetTo
(B_ORIGIN
);HelloView
*aView
= newHelloView
(gWindowSize
, "HelloView"); // add view to windowaWindow
->AddChild
(aView
); // make window visibleaWindow
->Show
(); // Start the application runningmyApplication
->Run
(); // After it is finished running, delete it // to be nice and tidy delete(myApplication
); return(0); }
This is a very simple app. All it needs is a specialized view to be added to the window and you're all set. You can use this as a template for knocking out those quick and dirty apps where you just want to try something out in a window real quick.
If all your view does is draw something, you could conceivably create a simple base class view that you could install a drawing function into. It would then in turn call this drawing function whenever the Draw() method was called.
Fun things can be done with this. If you haven't already started playing with filters, then maybe this gives you some incentive. They really are flexible and allow you to quickly and dynamically change the nature of your application simply by installing and removing filters.
How can filters be used for an interface builder? Maybe that's what someone can do next?
CHRP had the right goal: To create a hardware standard around the PowerPC similar in intent to what IBM's PC/AT became for the Intel processor, the core platform around which a huge industry was built. Almost forgotten is that while IBM designed the PC/AT, it lost control of the standard. It was IBM's very loss of control that gave birth to the clone industry, now driven, if not controlled, by Intel and Microsoft.
This bit of history isn't lost on Apple's management. They remember IBM's futile attempt to regain control of the PC standard with the proprietary PS/2 platform and have concluded that even with a hypothetical "private" version of CHRP, they would lose the hardware battle. In many respects, CHRP would have been a bigger danger to Apple than Power Computing ever was: Power's engineers were industrious and talented—had CHRP lived, industry and talent wouldn't have been necessary. Lower the bar and increase the competition.
Regardless of what we think of Apple's decision to bring the Mac cloning experiment to an end, the demise of CHRP is a logical consequence of the de-cloning move. Yet, many have stated their opinion that there is life left in CHRP—potentially. As a result, we've seen several suggestions on the 'Net with a view to breathing commercial life back into an "independent" PowerPC platform.
These observers go on to suggest there must be a considerable inventory of CHRP systems or, if not systems, ready-to-assemble components otherwise condemned to the scrap heap. The performance of CHRP hardware demonstrated by Motorola and IBM is enticing; why not use cost-competitive, if not "devalued" CHRP hardware to build a BeOS-based "Photoshop box"?
This is an engaging suggestion, and the thought experiment it triggers will allows us to explore issues such as dedicated systems vs. general purpose ones, the cost and performance benefits of the BeOS for a given application space and porting existing applications vs. enabling new ones.
If I follow the dominoes correctly, Photoshop has a large user base, these users are hungry for performance, or cost savings, or both, and many would buy one or more additional "boxes" just to run Photoshop if they saw enough productivity gains in a dedicated machine. A dual processor CHRP system just running a BeOS version of Photoshop would excite a large enough user population to incite one or more hardware manufacturers to ship such a product. In turn, this would constitute a sizeable enough business to trigger Adobe into making Photoshop available for this system.
This, needless to say, is purely hypothetical and I don't want to imply that any of the companies mentioned or alluded to have expressed the slightest shadow of interest for the idea. This is purely a thought experiment.
Even with this stipulation, I won't speculate too much as to why Adobe would or wouldn't consider such an idea. Performance is always welcome by Photoshop users and we've demonstrated substantial improvements on existing hardware as well as on affordable multi-processor systems.
Still, if I dare to imagine Adobe's concerns, there must be the cost of producing a new version of Photoshop and there must be the alternative of the Intel space. In the latter, there is inexpensive dual-processor hardware and interesting performance improvements in the making. I don't know what would happen if Adobe would let it be known they'd support the concept of a dedicated Photoshop system. Where would the best bids come from?
In the past, dedicated systems haven't fared too well. Take the word processor. In the early difficult days of the Mac, many observers remarked on the ease of use and beautiful printing obtained with MacWrite. They concluded the Mac should be reconfigured as a dedicated word processor. That didn't happen. Does this apply to the current idea? On the one hand customers have shown a liking for a system with a wide range of actual or potential uses. On the other hand, word processing applications are not driven by the thirst for performance Photoshop users experience.
Addressing cost, using the BeOS in a dedicated configuration might do more than add performance. Using the modularity of the BeOS and targeting Photoshop users could further reduce the footprint of the system and thus save hardware dollars. Still, others will remind us that hardware ought to stay as close as possible to the mainstream in order to best capture the benefits of competition between vendors.
Lastly, there is the question of new software versus mature applications. On this issue, the assumptions of today's thought experiment matter a great deal. Historically, ports from one generation of operating systems to a new one don't do well. The reasons might be that the technical constraints of the old design don't permit effective use of the new platform, or it could be that the press of business on the existing front leaves no financial or psychic energy for a risky bet on a new vehicle. (DOS to Windows, or Apple II to Mac are changes of generation; Mac to Windows isn't; Mac or Windows to the BeOS are.)
What differs in today's thought experiment is the assumption that a dedicated box would be sold almost exclusively to existing Photoshop users who want the simplest, least disruptive, most effective way of improving their existing work flow. In such a context a port could do very well.
It is too early to tell if the many suggestions we've seen on the 'Net for a "Photoshop box" will lead to an actual implementation, but we certainly appreciate the positive sentiments they convey.