Your SlideShare is downloading. ×
Three Objectionable Things
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

Three Objectionable Things

1,285
views

Published on

My lightning keynote talk at the ACCU 2011 software development conference. …

My lightning keynote talk at the ACCU 2011 software development conference.

This talks about three Objective C language features and how they came together to solve a problem in a "simple" and "elegant" way.

Published in: Technology, Economy & Finance

2 Comments
1 Like
Statistics
Notes
  • Thanks.

    The main font is the freely available League Gothic.

    Get it here: http://www.theleagueofmoveabletype.com/fonts/7-league-gothic
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Hey Pete, great presentation.
    btw, what is the font you are using ?
    Cheers
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
1,285
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
10
Comments
2
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. THREEOBJECTIONABLETHINGSPETE GOODLIFFE ACCU 2011, Oxford, UK
  • 2. @petegoodliffepete@goodliffe.netgoodliffe.blogspot.comwww.goodliffe.net PETE PROG GOOD LIFFE RAMMER / AUTHOR / C OLUMNIST / TEACHER CO NSCIENTIOUS CODER
  • 3. class UrbEngine{ void SetSequenceUsed(int sequence, bool used); ! float *GetLeftMainInMax() {return &_left_main_in_max;};public: ! bool IsSequenceUsed(int sequence); ! float *GetRightMainInMax() {return &_right_main_in_max;};! //get singleton instance ! bool ExportSequence(const char *filename, bool is_song, bool export_tracks); ! Effects *GetEffectsPtr();! //static UrbEngine &UrbEngine::GetInstance(); ! bool SaveSongSequence(BlueFile *file); ! void *LoadInsertEffectPlugin(int which_pad, int which_insert, const char *filePath); ! bool LoadSongSequence(BlueFile *file); ! void *LoadTrackInsertEffectPlugin(int which_insert, int which_track, const char *filePath)! UrbEngine(); ! void SetSequenceView(SEQUENCE_VIEW which_view); ! void CreateInsertEditor(int which_pad, int which_insert);! virtual ~UrbEngine(); ! SEQUENCE_VIEW GetSequenceView(); ! void CreateTrackInsertEditor(int which_track, int which_insert); ! void CreateInstrumentPluginEditor();! float GetProgramEditQLinkParameter(int which_pad, int qlink_index, char *formattedValueString); ! //track ! void SetVolume(float volume){_volume = volume;};! void SetProgramEditQLinkParameter(int which_pad, int qlink_index, float value); SetTrackName(int which_sequence, int track, const string &name); ! void ! float GetVolume() {return _volume;};! //void getParameterLabel(int index, char *label); ! const string &GetTrackName(int which_sequence, int track); ! void SetBank(int bank) {_bank = bank;};! //void getParameterDisplay(int index, char *text); ! void SetCurrentTrackName(const char *text); ! int GetBank() {return _bank;};! //void getParameterName(int index, char *text); ! const string &GetCurrentTrackName(); ! void SetUIListener(UrbUIListener *listener)! void setSampleRate(float sampleRate); ! void SetTrackProgramName(int track, const string &program_name); ! {! float GetSamplerate()! { return _sample_rate; } ! const string &GetTrackProgramName(int track); ! ! _ui_listener = listener; ! ! _sequencer.SetUIListener(listener);//Sequencer needs to fire UI commands as w! void setBlockSize(int blockSize); ! //void SetTimeSignature(int beats_per_bar, int beat_length); ! };! int GetBlockSize(); ! int GetCurrentBeatsPerBar(); ! UrbUIListener *GetUIListener() {return _ui_listener;};!! void SetOutputLatencySamples(int latencySamples); ! ! class Engine int GetCurrentBeatLength(); inline void ConvertEventTimesAbsoluteToBarOffset(); ! ! AudioRecorder &GetAudioRecorder() {return _audio_recorder;}; Sequencer &GetSequencer() {return _sequencer;};!! int getNumMidiInputChannels () { return 16; }! ! void TriggerMidiCC(int deltaFrames, int index, float value); ! !! { ! ///< Returns number of MIDI input channels used [0, 16] void SetSequenceLength(long length); ! ! SamplePool &GetSamplePool() {return _sample_pool;}; inline bool AdjustEventTimeToTimeSignature(long &time_code, int old_beats_per_bar, int new_beats_per_bar, int old_beat_length, int new_beat_length); Sample *SetSamplingActive(bool active);! void TriggerNote(int deltaFrames, int padKey, bool note_on, float velocity); ! long GetSequenceLength(); ! void CreatePluginProgram(const char *file_path);!! void SetPadAftertouchAmount(int pad, int after_touch_amount); ! ! public: void TriggerPad(int deltaFrames, int padKey, bool note_on, float velocity);void SetCurrentSequenceLength(long new_track_length); ! MidiPort *OpenMidiPort(string &port_name); long GetCurrentSequenceLength(); ! void AddInstrumentPluginToList(void *effect, Program *program);!! int GetPadAftertouchAmount(int pad); void SoloInstrument(int which_track, bool solo); ! ! //get singleton instance float GetCurrentNumQuarterNotes(); ! void AddSequenceEvent(int note, long timeCode, long length, float value, SequenceEvent::EV! void PlayAuditionSample(const char *filename); ! ! ! //static UrbEngine &UrbEngine::GetInstance(); void SetCurrentSequenceLoopEnd(long new_loop_end); ! Track *GetTrack(int which_sequence = -1, int track = -1, bool create_if_nonexistant = false); ! void ChangeSequenceEventIndex(int index, long timeCode, int newIndex, SequenceEvent::EVENT void ChangeSequenceEventPosition(int note, long timeCode, int newNote, long newPosition, S! void StopAuditionSample(); ! void SetCurrentTrackIndex(int track); ! void ChangeSequenceEventTimeCode(int note, long timeCode, long newPosition, SequenceEvent:! int LoadSample(const char *filename, DrumProgram *program, int !instrument =int GetCurrentTrackIndex(); -1, int whichlayer = -1); ! void ChangeSequenceEventLength(int note, long timeCode, long newLength);! void SetSampleBuffer(void *wave_buffer, int length, int channels, int wave_sample_rate, vector<SliceInfo> &slice_info); ! void UpdateCurrentTrack(); ! void ChangeSequenceEventValue(int note, long timeCode, float newValue, SequenceEvent::EVEN!! void SetupSlicePositionsFromWaveMargin(int which_margin); void SetFilterCoefficients(); ! ! ! Engine(); void ClearPattern(); void SetTrackVolume(int track, float volume); ! ! void ChangeSequenceEventTimeCodeAndValue(int index, long timeCode, long newPosition, float void DeleteSequenceEvent(int note, long timeCode, SequenceEvent::EVENT_TYPE type);! void TriggerSimpleEvent(long note, float velocity); ! float GetTrackVolume(int track); ! void AddProgramParameterCommand(int which_pad, int qlink_index, float value);!! ! virtual ~Engine(); //void InstrumentNoteOn(Program *program, long delta, SequenceEvent *sequence_event); ! void SetTrackPan(int track, float pan); void InternalNoteOn(Instrument *instrument_ptr, long delta, SequenceEvent *sequence_event, int base_note); ! float GetTrackPan(int track); ! void AddTimeSignature(int bar_position, int numerator, int denominator);! void AddPluginMidiMessage(UrbPluginMidiMessage &pluginMidiMessage); ! bool IsCurrentTrackMute(); ! void MoveTimeSignature(int bar_position, int new_bar_position);! void GroupNoteOff(int group, long delta, Program *which_program); ! void SoloTrack(int track, bool solo); ! void ChangeTimeSignature(int bar_position, int numerator, int denominator);! void NoteOff (long note, long delta, Program *which_program = 0); ! void MuteTrack(int track, bool mute); ! void DeleteTimeSignature(int bar_position);!! void SetCrunchMode(int crunch_mode); void SetFactoryContentDirectory(const char *dir); ! ! float GetProgramEditQLinkParameter(int which_pad, int qlink_index, char void ClearTracksWithProgram(Program *program); ! INTu GetSequenceNumberOfUsedTracks(INTs which_sequence = -1); ! QLinkMap *ChangeQLinkValue(int qlink, float value);! std::string &GetFactoryContentDirectory(); *formattedValueString);//static void QuantizeTimeCode(long &time_code, float swing_level, long quantization_value, bool quantize_to_beginning); ! //program! void SetSequenceEventValue(int event_index, float value);! void SetSequenceTempo(float tempo); ! ! ! void SetProgramEditQLinkParameter(int which_pad, int qlink_index, float value); void SetTrackProgram(int track, Program *program); Program *GetTrackProgram(int track); ! ! //const int GetMidiMessageCount(); //const UrbMidiMessage &GetMidiMessage(int i);! void CalculateSamplesPerPulse(); ! void SetCurrentTrackProgram(Program *program); ! void SetMidiPortListener(MidiPortListener *listener) {_midi_port_listener = listener;};!! vector<SequenceEvent>::iterator DeleteSequenceEvent(int event_index); int GetSelectedInstrument(); ! ! //void getParameterLabel(int index, char *label); inline void CheckForSequenceRunnerBounds(); ! MidiPortListener *GetMidiPortListener(){return _midi_port_listener;};! void SetSelectedInstrument(int instrument); ! ! //void getParameterDisplay(int index, char *text); //events ! ! CommandManager &GetCommandManager(){ return _command_manager;}; const string &GetFolderPath(int which_folder){return _folder_path[which_folder];};! bool SetInstrumentNameIfSingle(int whichone, const string &name); ! inline void ResyncTrackEventIndex(Track *track, int track_index); ! void SetFolderPath(int which_folder, string path);!! string &GetSelectedWaveFileName(); ! string &GetSelectedWaveFileName(int instrument, int whichlayer); ! ! //void getParameterName(int index, char *text); inline void ResyncEventIndices(); void TriggerSequenceEvents(long sampleFrames); ! ! void SetTrackMeteringActive(bool active) {_track_metering_active = active;}; list<Track*> &GetTrackRenderList() {return _track_render_list;};!! void writepresetsarray(); vector<int> &GetSongPatternList(); ! ! ! void setSampleRate(float sampleRate); void ClearInstrumentEvents(int instrument_to_clear=-1); void CutInstrumentEvents(int instrument_to_cut = -1); ! void initProcess();! int GetCrunchMode(); ! void CopyInstrumentEvents(int instrument_to_copy = -1); ! inline float saturate(float x);!! void SetSliceSensitivity(float slice_sensitivity); int GetPadMode(); ! ! float GetSamplerate()! void PasteInstrumentEvents(int instrument_to_paste = -1); ! ! void RecordSequenceEvent(int deltaFrames, SequenceEvent temp_sequence_event, bool add_command ! false, int inline = -1); = track void Crunch(float &x);! //int PadControlClicked(int index, float value); ! void SetSequenceEventLength(int deltaFrames, int note, int track = -1); ! void WriteFloatValue(float value, FILE *file);! void NewSong(); ! //void SetAutoQuantize(bool auto_quantize); ! float ReadFloatValue(FILE *file);! ! //bool IsAutoQuantize(); ! void BounceValue(float &value);! string &GetPluginDirectory(); ! void SortSequenceEventList();! unsigned long GetVersionNumber(){return _version_number;}; ! //void SortSequenceEventList(int &event_index); ! void ActionMove();! void DoPatternSequenceFunction(int value, int selected_pattern); ! long GetQuantizationValue();! void DeleteGroup(int which_group); ! void SetQuantizeMode(int mode); ! void SetupSliceEvents();! ! int GetQuantizeMode(); ! void DetectAndSetSlices(int sample_index, int channels, int sf_phrase_length, int sf_lengt! void SetInstrumentGroup(int which_instrument, float whichGroup); ! inline long QuantizeTimeCode(long &time_code); //returns the quantized time code before swing ! void InitProgram(int p);! int GetInstrumentGroup(int which_instrument); ! ! void KillOldestVoice(); inline long QuantizeTimeCode(long &time_code, float swing_level, long quantization_value, bool quantize_to_beginning); //returns the quantized time code before swing ! void Quantize(); ! int FindVoiceEffectBuffer(int pad, Track *track, Program *program);! bool IsInstrumentMute(int which_instrument); ! void PasteSequenceEventsFromCopyBuffer(); ! void AddTrackToMixerList(Track *which_track); ! //long GetPPQN(); ! std::string _factory_content_directory;! //void DeleteDoubleEntries(); ! void MatchProgramsToSequence(); !! ! void SetNoteRepeatActive(bool active); ! float _volume;! //drum program ! bool IsNoteRepeatActive();! void SetCurrentProgramName(const char* name); ! void SetNoteEraseActive(bool active); ! string _empty_string;! const char *GetCurrentProgramName();! ! bool IsNoteEraseActive(); ! float fprogramname;! //const char *GetSelectedFxParameterName(int index); ! Program *CreateNewProgram(PROGRAM_TYPE type);! bool *GetPadTriggered(); ! Program *CreatePluginProgram(const char *file_path, bool setprogram); ! CommandManager _command_manager;! bool LoadLoopIntoSequence(const char *path, int sequence); ! void SetPluginProgram (PluginProgram *program);! //bool ImportLoop(const char *filename, bool repeat_or_truncate_old_pattern); ! void SetPluginProgram(const char *plugin_name); ! int _last_delta;! Program *GetCurrentProgram(); ! void DeleteDoubleEntries(); ! float fScaler;! void SetProgramType(int type); ! Buffers _buffers;! void ClearProgram(Program *program, bool clear_associated_patterns); ! Voice voice[MAXVOICES+1];! SamplePool *GetSamplePoolPtr(); ! //actions ! bool _pad_triggered[16];! ! void ActionAddSequenceEvent(SequenceEvent &event_to_add); ! int _pad_aftertouch_amount[16];! int GetNumberOfSlices(); ! void ActionAddSequenceEventToCopyBuffer(SequenceEvent &event_to_add);! //void SetChannelMode(int channel_mode); ! void ActionClearCopyBuffer(); ! bool _output_active[NUM_STEREO_OUTS];! FunctionMapper *GetFunctionMapper(){return &_function_mapper;};! long ActionSetAutomationEventPosition(SequenceEvent &sequence_event_to_set, float value, long ! position); int mRenderStatus;! ParameterMapper *GetParameterMapper(){return &_parameter_mapper;}; ! int ActionSetSequenceEventIndex(SequenceEvent &sequence_event_to_set, int index); ! !! LastConfigAction *GetLastMappedAction() {return &_last_config_action;}; ! ! long ActionSetSequenceEventPosition(SequenceEvent &sequence_event_to_set, int note, long position); RingBuffer _ring_buffer;! ! long ActionSetSequenceEventTimeCode(SequenceEvent &sequence_event_to_set, long position); !! int GetFunctionTagFromNote(int note) {return _function_mapper.GetFunctionTagFromNote(note);}; ! long ActionSetSequenceEventLength(SequenceEvent &sequence_event_to_set, long length); ! //vector<UrbMidiMessage> _midi_messages;! void SetFunctionNote(int function_slot, int note, bool learn) {_function_mapper.SetNote(function_slot, note, learn);}; ! ! vector<UrbPluginMidiMessage> _plugin_midi_messages; void ActionSetSequenceEventTimeCodeAndValue(SequenceEvent &sequence_event_to_set, long time_code, float value! int GetParameterFromMidiCC(int controlID) {return _parameter_mapper.GetParameterFromMidiCC(controlID);}; ! ! ! ! ! ! ! ! ! ! ! MidiPortListener *_midi_port_listener; ! ! , long! void SetParameterMidiCC(int parameter_slot, int midi_cc, bool learn) {_parameter_mapper.SetMidiCC(parameter_slot, midi_cc, true);}; previous_time_code, float previous_value); ! //vector<MidiPort> _midi_port;! //void RecordSample(float **inputs, const long sampleFrames); ! float ActionSetSequenceEventValue(SequenceEvent &sequence_event_to_set, float value); !! Sample *CreateSampleFromRecordingChain(); ! void ActionDeleteSequenceEvent(SequenceEvent &event_to_delete); ! int _pad_mode;! void ClearRecordingChain();! void Process (float **inputs, float **outputs, long sampleFrames, bool replacing, bool realtime = true); ! //Time signature actions ! struct InstrumentPlugin! void SetCurrentProgram(Program *program); ! void ActionAddTimeSignature(int bar_position, int numerator, int denominator); ! {! bool IsExporting() { return _exporting;}; ! void ActionMoveTimeSignature(int bar_position, int new_bar_position); ! ! InstrumentPlugin(void *effect_, Program *program_)! bool ExportSequence(const char *filename, bool is_song, bool export_tracks); ! void ActionChangeTimeSignature(int bar_position, int numerator, int denominator); ! ! {! float *GetLeftMainOutMax() {return &_left_main_out_max;}; ! void ActionDeleteTimeSignature(int bar_position); ! ! ! effect = effect_;! float *GetRightMainOutMax() {return &_right_main_out_max;}; ! ! bool GetTimeSignatureNumeratorAndDenominator(int bar_position, int &numerator, int &denominator); ! ! program = program_;! float *GetLeftMainInMax() {return &_left_main_in_max;}; ! ! };! float *GetRightMainInMax() {return &_right_main_in_max;}; ! ! void *effect;! Effects *GetEffectsPtr(); ! void AddNoteOnEvent(int which_sequence, int which_track, int channel, long time, int note, int velocity); ! ! Program *program; ! ! }; void AddNoteOffEvent(int which_sequence, int which_track, int bars, int channel, long time, int note, int velocity);
  • 4. 3
  • 5. why?
  • 6. GOODLIFFE // PAY ATTENTION! 15 minutes!
  • 7. ASPIDISTRA #1
  • 8. ✔ Play theme tune (AVAudioPlayer)✘ Fade in/out
  • 9. Objective-C
  • 10. Objective-C categoriesassociative references blocks
  • 11. ROMAN TRAVELOGUE#2
  • 12. PROBLEM#1 a nice the API
  • 13. categories(because one interface is never enough)
  • 14. AVAudioPlayer *player = … ;[player play];[player stop];
  • 15. AVAudioPlayer *player = … ;[player play];[player stop];[player playWithFadeDuration:1.0];[player stopWithFadeDuration:1.0];
  • 16. @interface AVAudioPlayer{ …}- (id) initWithContentsOfURL:(NSURL*)url;- (void) play;- (void) stop;@end
  • 17. @interface AVAudioPlayer{ …}- (id) initWithContentsOfURL:(NSURL*)url;- (void) play;- (void) stop;- (void) playWithFadeDuration:(float)secs;- (void) stopWithFadeDuration:(float)secs;@end
  • 18. @interface AVAudioPlayer (Fades)- (void) playWithFadeDuration:(float)secs;- (void) stopWithFadeDuration:(float)secs;@end
  • 19. @implementation AVAudioPlayer (Fades)- (void) playWithFadeDuration:(float)secs{ // magic happens here}- (void) stopWithFadeDuration:(float)secs{ // clever stuff in here}@end
  • 20. AVAudioPlayer *player = … ;[player play];[player stop];[player playWithFadeDuration:1.0];[player stopWithFadeDuration:1.0]; ✔
  • 21. THIS IS NOT ASUBLIMINALMESSAGE
  • 22. EQUIDISTANT CAMOMILE#4
  • 23. PROBLEM#2 we need some new instance variables
  • 24. associative references (a posh name for cheating)
  • 25. static const char volumeLevelKey = ‘Q’;NSNumber number = [NSNumber numberWithFloat:1.0];objc_setAssociatedObject(self, &volumeLevelKey, &variable, OBJ_ASSOCIATION_RETAIN_NONATOMIC);
  • 26. NSNumber *number = (NSNumber*)objc_getAssociatedObject(self, &volumeLevelKey);
  • 27. @interface AVAudioPlayer (Fades)- (void) playWithFadeDuration:(float)secs;- (void) stopWithFadeDuration:(float)secs;@property float fadeVolume;@end
  • 28. - (void) fadeVolume{ // gibberish in here}- (void) setFadeVolume{ // cobblers in here} ✔float fadeVolume = player.fadeVolume;
  • 29. A TRAVESTY OF PYLON#6
  • 30. PROBLEM#3 we need to use another fancy language feature
  • 31. blocks(because C++ isn’t the only cool language)
  • 32. PROBLEM#3 when a fade has completed, do “something”
  • 33. typedef void (^FadeCompleteBlock)();
  • 34. typedef void (^FadeCompleteBlock)();- (void) fadeToVolume:(float)volume withDuration:(float)secs andThen:(FadeCompleteBlock)action
  • 35. typedef void (^FadeCompleteBlock)();- (void) fadeToVolume:(float)volume withDuration:(float)secs andThen:(FadeCompleteBlock)action[player fadeToVolume:0.0 withDuration:1.0 andThen:^{ [player stop]; player.volume = 1.0; }];
  • 36. TRANSCENDENTAL SHOE #7
  • 37. the morale of the story (there is none)
  • 38. QA &Pete Goodliffe @petegoodliffe pete@goodliffe.net
  • 39. @petegoodliffepete@goodliffe.netgoodliffe.blogspot.comwww.goodliffe.net
  • 40. i knew you’d want another[UIView animateWithDuration:0.5 animations:^{ imageView.layer.opacity = 0.1; } completion:^(BOOL finished){ [imageView removeFromSuperview]; }
  • 41. BUMPH DULL, but importantTHIS DOCUMENT WAS CREATED BY PETE GOODLIFFE IT IS COPYRIGHT // © 2011 PETE GOODLIFFE>> ALL RIGHTS RESERVED>> ALL THOUGHTS ARE OWNED>> PHOTOS AND IMAGES ARE MOSTLY SOURCED FROM THE WEBTHANK YOU FOR READING // I HOPE IT WAS USEFUL Version 1.0 2011-04-04