├── .gitignore ├── Builds └── MacOSX │ ├── Info-App.plist │ ├── OSCTimecode.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── RecentFilesMenuTemplate.nib ├── JuceLibraryCode ├── AppConfig.h ├── JuceHeader.h ├── ReadMe.txt ├── juce_audio_basics.cpp ├── juce_audio_basics.mm ├── juce_audio_devices.cpp ├── juce_audio_devices.mm ├── juce_audio_formats.cpp ├── juce_audio_formats.mm ├── juce_audio_processors.cpp ├── juce_audio_processors.mm ├── juce_core.cpp ├── juce_core.mm ├── juce_cryptography.cpp ├── juce_cryptography.mm ├── juce_data_structures.cpp ├── juce_data_structures.mm ├── juce_events.cpp ├── juce_events.mm ├── juce_graphics.cpp ├── juce_graphics.mm ├── juce_gui_basics.cpp ├── juce_gui_basics.mm ├── juce_gui_extra.cpp ├── juce_gui_extra.mm ├── juce_opengl.cpp ├── juce_opengl.mm ├── juce_osc.cpp ├── juce_video.cpp └── juce_video.mm ├── README.md ├── Screenshots ├── screenshot-receiver.png └── screenshot-sender.png └── Source ├── LookAndFeel └── CustomLookAndFeel.hpp ├── Main.cpp ├── MainComponent.cpp ├── MainComponent.h ├── TimeCode.cpp ├── TimeCode.hpp ├── TimeLabel.cpp ├── TimeLabel.hpp └── test ├── TimeCodeTest.cpp └── TimeCodeTest.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | Builds/MacOSX/build/ 3 | Builds/MacOSX/OSCTimecode.xcodeproj/project.xcworkspace/xcuserdata/ 4 | *.jucer 5 | 6 | # Created by https://www.gitignore.io/api/xcode,osx 7 | 8 | ### Xcode ### 9 | # Xcode 10 | # 11 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 12 | 13 | ## Build generated 14 | build/ 15 | DerivedData/ 16 | 17 | ## Various settings 18 | *.pbxuser 19 | !default.pbxuser 20 | *.mode1v3 21 | !default.mode1v3 22 | *.mode2v3 23 | !default.mode2v3 24 | *.perspectivev3 25 | !default.perspectivev3 26 | xcuserdata/ 27 | 28 | ## Other 29 | *.moved-aside 30 | *.xccheckout 31 | *.xcscmblueprint 32 | 33 | 34 | ### OSX ### 35 | .DS_Store 36 | .AppleDouble 37 | .LSOverride 38 | 39 | # Icon must end with two \r 40 | Icon 41 | 42 | 43 | # Thumbnails 44 | ._* 45 | 46 | # Files that might appear in the root of a volume 47 | .DocumentRevisions-V100 48 | .fseventsd 49 | .Spotlight-V100 50 | .TemporaryItems 51 | .Trashes 52 | .VolumeIcon.icns 53 | 54 | # Directories potentially created on remote AFP share 55 | .AppleDB 56 | .AppleDesktop 57 | Network Trash Folder 58 | Temporary Items 59 | .apdisk 60 | -------------------------------------------------------------------------------- /Builds/MacOSX/Info-App.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CFBundleExecutable 7 | ${EXECUTABLE_NAME} 8 | CFBundleIconFile 9 | 10 | CFBundleIdentifier 11 | $(PRODUCT_BUNDLE_IDENTIFIER) 12 | CFBundleName 13 | OSCTimecode 14 | CFBundleDisplayName 15 | OSCTimecode 16 | CFBundlePackageType 17 | APPL 18 | CFBundleSignature 19 | ???? 20 | CFBundleShortVersionString 21 | 1.0.0 22 | CFBundleVersion 23 | 1.0.0 24 | NSHumanReadableCopyright 25 | 26 | NSHighResolutionCapable 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Builds/MacOSX/OSCTimecode.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Builds/MacOSX/RecentFilesMenuTemplate.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hautetechnique/OSCTimeCode/2f2d4ba445350c3e00977c2fd7dafa0eaba3a8e0/Builds/MacOSX/RecentFilesMenuTemplate.nib -------------------------------------------------------------------------------- /JuceLibraryCode/AppConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | There's a section below where you can add your own custom code safely, and the 7 | Projucer will preserve the contents of that block, but the best way to change 8 | any of these definitions is by using the Projucer's project settings. 9 | 10 | Any commented-out settings will assume their default values. 11 | 12 | */ 13 | 14 | #ifndef __JUCE_APPCONFIG_OEWIXR__ 15 | #define __JUCE_APPCONFIG_OEWIXR__ 16 | 17 | //============================================================================== 18 | // [BEGIN_USER_CODE_SECTION] 19 | 20 | // (You can add your own code in this section, and the Projucer will not overwrite it) 21 | 22 | // [END_USER_CODE_SECTION] 23 | 24 | //============================================================================== 25 | #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 26 | #define JUCE_MODULE_AVAILABLE_juce_audio_devices 1 27 | #define JUCE_MODULE_AVAILABLE_juce_audio_formats 1 28 | #define JUCE_MODULE_AVAILABLE_juce_audio_processors 1 29 | #define JUCE_MODULE_AVAILABLE_juce_core 1 30 | #define JUCE_MODULE_AVAILABLE_juce_cryptography 1 31 | #define JUCE_MODULE_AVAILABLE_juce_data_structures 1 32 | #define JUCE_MODULE_AVAILABLE_juce_events 1 33 | #define JUCE_MODULE_AVAILABLE_juce_graphics 1 34 | #define JUCE_MODULE_AVAILABLE_juce_gui_basics 1 35 | #define JUCE_MODULE_AVAILABLE_juce_gui_extra 1 36 | #define JUCE_MODULE_AVAILABLE_juce_opengl 1 37 | #define JUCE_MODULE_AVAILABLE_juce_osc 1 38 | #define JUCE_MODULE_AVAILABLE_juce_video 1 39 | 40 | //============================================================================== 41 | #ifndef JUCE_STANDALONE_APPLICATION 42 | #ifdef JucePlugin_Build_Standalone 43 | #define JUCE_STANDALONE_APPLICATION JucePlugin_Build_Standalone 44 | #else 45 | #define JUCE_STANDALONE_APPLICATION 1 46 | #endif 47 | #endif 48 | 49 | #define JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED 1 50 | 51 | //============================================================================== 52 | // juce_audio_devices flags: 53 | 54 | #ifndef JUCE_ASIO 55 | //#define JUCE_ASIO 56 | #endif 57 | 58 | #ifndef JUCE_WASAPI 59 | //#define JUCE_WASAPI 60 | #endif 61 | 62 | #ifndef JUCE_WASAPI_EXCLUSIVE 63 | //#define JUCE_WASAPI_EXCLUSIVE 64 | #endif 65 | 66 | #ifndef JUCE_DIRECTSOUND 67 | //#define JUCE_DIRECTSOUND 68 | #endif 69 | 70 | #ifndef JUCE_ALSA 71 | //#define JUCE_ALSA 72 | #endif 73 | 74 | #ifndef JUCE_JACK 75 | //#define JUCE_JACK 76 | #endif 77 | 78 | #ifndef JUCE_USE_ANDROID_OPENSLES 79 | //#define JUCE_USE_ANDROID_OPENSLES 80 | #endif 81 | 82 | //============================================================================== 83 | // juce_audio_formats flags: 84 | 85 | #ifndef JUCE_USE_FLAC 86 | //#define JUCE_USE_FLAC 87 | #endif 88 | 89 | #ifndef JUCE_USE_OGGVORBIS 90 | //#define JUCE_USE_OGGVORBIS 91 | #endif 92 | 93 | #ifndef JUCE_USE_MP3AUDIOFORMAT 94 | //#define JUCE_USE_MP3AUDIOFORMAT 95 | #endif 96 | 97 | #ifndef JUCE_USE_LAME_AUDIO_FORMAT 98 | //#define JUCE_USE_LAME_AUDIO_FORMAT 99 | #endif 100 | 101 | #ifndef JUCE_USE_WINDOWS_MEDIA_FORMAT 102 | //#define JUCE_USE_WINDOWS_MEDIA_FORMAT 103 | #endif 104 | 105 | //============================================================================== 106 | // juce_audio_processors flags: 107 | 108 | #ifndef JUCE_PLUGINHOST_VST 109 | //#define JUCE_PLUGINHOST_VST 110 | #endif 111 | 112 | #ifndef JUCE_PLUGINHOST_VST3 113 | //#define JUCE_PLUGINHOST_VST3 114 | #endif 115 | 116 | #ifndef JUCE_PLUGINHOST_AU 117 | //#define JUCE_PLUGINHOST_AU 118 | #endif 119 | 120 | //============================================================================== 121 | // juce_core flags: 122 | 123 | #ifndef JUCE_FORCE_DEBUG 124 | //#define JUCE_FORCE_DEBUG 125 | #endif 126 | 127 | #ifndef JUCE_LOG_ASSERTIONS 128 | //#define JUCE_LOG_ASSERTIONS 129 | #endif 130 | 131 | #ifndef JUCE_CHECK_MEMORY_LEAKS 132 | //#define JUCE_CHECK_MEMORY_LEAKS 133 | #endif 134 | 135 | #ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES 136 | //#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES 137 | #endif 138 | 139 | #ifndef JUCE_INCLUDE_ZLIB_CODE 140 | //#define JUCE_INCLUDE_ZLIB_CODE 141 | #endif 142 | 143 | #ifndef JUCE_USE_CURL 144 | //#define JUCE_USE_CURL 145 | #endif 146 | 147 | #ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS 148 | //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 149 | #endif 150 | 151 | #ifndef JUCE_ALLOW_STATIC_NULL_VARIABLES 152 | //#define JUCE_ALLOW_STATIC_NULL_VARIABLES 153 | #endif 154 | 155 | //============================================================================== 156 | // juce_graphics flags: 157 | 158 | #ifndef JUCE_USE_COREIMAGE_LOADER 159 | //#define JUCE_USE_COREIMAGE_LOADER 160 | #endif 161 | 162 | #ifndef JUCE_USE_DIRECTWRITE 163 | //#define JUCE_USE_DIRECTWRITE 164 | #endif 165 | 166 | //============================================================================== 167 | // juce_gui_basics flags: 168 | 169 | #ifndef JUCE_ENABLE_REPAINT_DEBUGGING 170 | //#define JUCE_ENABLE_REPAINT_DEBUGGING 171 | #endif 172 | 173 | #ifndef JUCE_USE_XSHM 174 | //#define JUCE_USE_XSHM 175 | #endif 176 | 177 | #ifndef JUCE_USE_XRENDER 178 | //#define JUCE_USE_XRENDER 179 | #endif 180 | 181 | #ifndef JUCE_USE_XCURSOR 182 | //#define JUCE_USE_XCURSOR 183 | #endif 184 | 185 | //============================================================================== 186 | // juce_gui_extra flags: 187 | 188 | #ifndef JUCE_WEB_BROWSER 189 | //#define JUCE_WEB_BROWSER 190 | #endif 191 | 192 | #ifndef JUCE_ENABLE_LIVE_CONSTANT_EDITOR 193 | //#define JUCE_ENABLE_LIVE_CONSTANT_EDITOR 194 | #endif 195 | 196 | //============================================================================== 197 | // juce_video flags: 198 | 199 | #ifndef JUCE_DIRECTSHOW 200 | //#define JUCE_DIRECTSHOW 201 | #endif 202 | 203 | #ifndef JUCE_MEDIAFOUNDATION 204 | //#define JUCE_MEDIAFOUNDATION 205 | #endif 206 | 207 | #ifndef JUCE_QUICKTIME 208 | //#define JUCE_QUICKTIME 209 | #endif 210 | 211 | #ifndef JUCE_USE_CAMERA 212 | //#define JUCE_USE_CAMERA 213 | #endif 214 | 215 | 216 | #endif // __JUCE_APPCONFIG_OEWIXR__ 217 | -------------------------------------------------------------------------------- /JuceLibraryCode/JuceHeader.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | This is the header file that your files should include in order to get all the 7 | JUCE library headers. You should avoid including the JUCE headers directly in 8 | your own source files, because that wouldn't pick up the correct configuration 9 | options for your app. 10 | 11 | */ 12 | 13 | #ifndef __APPHEADERFILE_OEWIXR__ 14 | #define __APPHEADERFILE_OEWIXR__ 15 | 16 | #include "AppConfig.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | 34 | #if ! DONT_SET_USING_JUCE_NAMESPACE 35 | // If your code uses a lot of JUCE classes, then this will obviously save you 36 | // a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE. 37 | using namespace juce; 38 | #endif 39 | 40 | #if ! JUCE_DONT_DECLARE_PROJECTINFO 41 | namespace ProjectInfo 42 | { 43 | const char* const projectName = "OSCTimecode"; 44 | const char* const versionString = "1.0.0"; 45 | const int versionNumber = 0x10000; 46 | } 47 | #endif 48 | 49 | #endif // __APPHEADERFILE_OEWIXR__ 50 | -------------------------------------------------------------------------------- /JuceLibraryCode/ReadMe.txt: -------------------------------------------------------------------------------- 1 | 2 | Important Note!! 3 | ================ 4 | 5 | The purpose of this folder is to contain files that are auto-generated by the Projucer, 6 | and ALL files in this folder will be mercilessly DELETED and completely re-written whenever 7 | the Projucer saves your project. 8 | 9 | Therefore, it's a bad idea to make any manual changes to the files in here, or to 10 | put any of your own files in here if you don't want to lose them. (Of course you may choose 11 | to add the folder's contents to your version-control system so that you can re-merge your own 12 | modifications after the Projucer has saved its changes). 13 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_audio_basics.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_audio_basics.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_audio_devices.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_audio_devices.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_audio_formats.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_audio_formats.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_audio_processors.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_audio_processors.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_core.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_core.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_cryptography.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_cryptography.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_data_structures.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_data_structures.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_events.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_events.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_graphics.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_graphics.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_gui_basics.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_gui_basics.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_gui_extra.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_gui_extra.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_opengl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_opengl.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_osc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_video.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /JuceLibraryCode/juce_video.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include "AppConfig.h" 9 | #include 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Binary 2 | 3 | A compiled binary download is available [here](https://github.com/hautetechnique/OSCTimeCode/releases). 4 | 5 | It is a C++ MacOS app that allows you to send and recieve OSCTimecode over ethernet. 6 | 7 | # Installation 8 | 9 | This example is written in Juce, C++ and tested for Mac and Windows. 10 | 11 | **Structure** 12 | 13 | OSC messages are structured like so: 14 | 15 | |*Type* | *String* | *Format* | 16 | |-----------|---------------|-------------------------------------------| 17 | |*Address* | /TC1/time/30 | / {TimeCode layer} / time / {Frames per second} | 18 | |*Argument* | 00:00:00:00 | HH:MM:SS:FF | 19 | 20 | The layer can be TC1 or TC2, representing TimeCode 1 or TimeCode 2 21 | 22 | **Screenshots** 23 | 24 | *Sender* 25 | 26 | ![Sender](/Screenshots/screenshot-sender.png?raw=true "Sender") 27 | 28 | *Receiver* 29 | 30 | ![Receiver](/Screenshots/screenshot-receiver.png?raw=true "Receiver") 31 | 32 | # References 33 | 34 | - [OSC wiki](https://en.wikipedia.org/wiki/Open_Sound_Control) 35 | - [TimeCode Live software](https://www.blckbook.nl) 36 | - [Juce](https://www.juce.com) 37 | -------------------------------------------------------------------------------- /Screenshots/screenshot-receiver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hautetechnique/OSCTimeCode/2f2d4ba445350c3e00977c2fd7dafa0eaba3a8e0/Screenshots/screenshot-receiver.png -------------------------------------------------------------------------------- /Screenshots/screenshot-sender.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hautetechnique/OSCTimeCode/2f2d4ba445350c3e00977c2fd7dafa0eaba3a8e0/Screenshots/screenshot-sender.png -------------------------------------------------------------------------------- /Source/LookAndFeel/CustomLookAndFeel.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | OSCTimecode - Juce OSC Timecode example application 3 | 4 | Copyright (C) 2017 Haute Technique - Sander ter Braak and Jan de Boer 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as 8 | published by the Free Software Foundation, either version 3 of the 9 | License, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library. 18 | 19 | If not, see . 20 | */ 21 | 22 | #ifndef CustomLookAndFeel_hpp 23 | #define CustomLookAndFeel_hpp 24 | 25 | #include "../JuceLibraryCode/JuceHeader.h" 26 | 27 | class CustomLookAndFeel : public LookAndFeel_V3 { 28 | 29 | public: 30 | 31 | 32 | Colour HAUTE_BLUE = Colour(0xFF169ee4); 33 | 34 | CustomLookAndFeel() 35 | { 36 | 37 | setColour(TextEditor::focusedOutlineColourId, Colours::white); 38 | setColour(TextEditor::ColourIds::highlightColourId, Colours::white); 39 | setColour(ListBox::ColourIds::backgroundColourId, Colours::darkgrey); 40 | 41 | setColour(TextButton::ColourIds::buttonColourId, Colour(0xFF606060)); 42 | setColour(TextButton::ColourIds::textColourOffId, Colour(0xffEFEFEF)); 43 | setColour(TextButton::ColourIds::textColourOnId, Colour(0xffEFEFEF)); 44 | 45 | setColour(TextEditor::ColourIds::outlineColourId, Colours::grey); 46 | setColour(TextEditor::ColourIds::focusedOutlineColourId, Colours::grey); 47 | 48 | setColour(TextEditor::backgroundColourId, Colours::black); 49 | setColour(TextEditor::ColourIds::highlightColourId, Colour(0xFF5dcffc)); 50 | setColour(TextEditor::ColourIds::textColourId, Colours::white); 51 | setColour(CaretComponent::ColourIds::caretColourId, Colour(0xFFFFFFFF)); 52 | 53 | setColour(Label::textColourId, Colours::white); 54 | } 55 | 56 | void drawButtonText (Graphics& g, TextButton& button, bool isMouseOverButton, bool /*isButtonDown*/) 57 | { 58 | Font font = g.getCurrentFont(); 59 | 60 | g.setFont (font); 61 | 62 | Colour c = button.findColour (button.getToggleState() ? TextButton::textColourOnId 63 | : TextButton::textColourOffId) 64 | .withMultipliedAlpha (button.isEnabled() ? 1.0f : 0.5f); 65 | 66 | if(isMouseOverButton) c = Colours::white; 67 | 68 | g.setColour (c); 69 | 70 | 71 | g.drawFittedText (button.getButtonText(), 72 | 0, 73 | 1, 74 | button.getWidth() , 75 | button.getHeight() , 76 | Justification::centred, 2); 77 | } 78 | 79 | void drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour, 80 | bool isMouseOverButton, bool isButtonDown) 81 | { 82 | Colour baseColour (backgroundColour.withMultipliedSaturation (button.hasKeyboardFocus (true) ? 1.3f : 0.9f) 83 | .withMultipliedAlpha (button.isEnabled() ? 0.9f : 0.5f)); 84 | 85 | if (isButtonDown || isMouseOverButton) 86 | baseColour = HAUTE_BLUE.contrasting (isButtonDown ? 0.4f : 0.2f); 87 | 88 | const bool flatOnLeft = button.isConnectedOnLeft(); 89 | const bool flatOnRight = button.isConnectedOnRight(); 90 | const bool flatOnTop = button.isConnectedOnTop(); 91 | const bool flatOnBottom = button.isConnectedOnBottom(); 92 | 93 | const float width = button.getWidth(); 94 | const float height = button.getHeight(); 95 | 96 | if (width > 0 && height > 0) 97 | { 98 | const float cornerSize = 5.0f; 99 | 100 | Path outline; 101 | outline.addRoundedRectangle (0, 0, width, height, cornerSize, cornerSize, 102 | ! (flatOnLeft || flatOnTop), 103 | ! (flatOnRight || flatOnTop), 104 | ! (flatOnLeft || flatOnBottom), 105 | ! (flatOnRight || flatOnBottom)); 106 | 107 | 108 | g.setColour(baseColour); 109 | g.fillPath(outline); 110 | 111 | 112 | const int bs = 1; 113 | 114 | Path fill; 115 | fill.addRoundedRectangle (bs, bs, width-(bs *2), height - (bs * 2), cornerSize, cornerSize, 116 | ! (flatOnLeft || flatOnTop), 117 | ! (flatOnRight || flatOnTop), 118 | ! (flatOnLeft || flatOnBottom), 119 | ! (flatOnRight || flatOnBottom)); 120 | 121 | if(isButtonDown) g.setColour(HAUTE_BLUE.withBrightness(0.6)); 122 | else if(isMouseOverButton) g.setColour(HAUTE_BLUE.withBrightness(0.3)); 123 | else g.setColour(Colours::black); 124 | 125 | g.fillPath(fill); 126 | 127 | } 128 | } 129 | }; 130 | 131 | 132 | #endif /* CustomLookAndFeel_hpp */ 133 | -------------------------------------------------------------------------------- /Source/Main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | OSCTimecode - Juce OSC Timecode example application 3 | 4 | Copyright (C) 2017 Haute Technique - Sander ter Braak and Jan de Boer 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as 8 | published by the Free Software Foundation, either version 3 of the 9 | License, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library. 18 | 19 | If not, see . 20 | */ 21 | 22 | #include "../JuceLibraryCode/JuceHeader.h" 23 | #include "MainComponent.h" 24 | 25 | 26 | //============================================================================== 27 | class OSCTimecodeApplication : public JUCEApplication 28 | { 29 | public: 30 | 31 | OSCTimecodeApplication() {} 32 | 33 | const String getApplicationName() override { return ProjectInfo::projectName; } 34 | const String getApplicationVersion() override { return ProjectInfo::versionString; } 35 | bool moreThanOneInstanceAllowed() override { return true; } 36 | 37 | 38 | void initialise (const String& commandLine) override 39 | { 40 | mainWindow = new MainWindow (getApplicationName()); 41 | } 42 | 43 | void shutdown() override 44 | { 45 | mainWindow = nullptr; 46 | } 47 | 48 | void systemRequestedQuit() override 49 | { 50 | quit(); 51 | } 52 | 53 | class MainWindow : public DocumentWindow 54 | { 55 | public: 56 | MainWindow (String name) : DocumentWindow (name, 57 | Colour(0xFF151515), 58 | DocumentWindow::allButtons) 59 | { 60 | setUsingNativeTitleBar (true); 61 | setContentOwned (new MainContentComponent(), true); 62 | 63 | centreWithSize (getWidth(), getHeight()); 64 | setVisible (true); 65 | } 66 | 67 | void closeButtonPressed() override 68 | { 69 | JUCEApplication::getInstance()->systemRequestedQuit(); 70 | } 71 | 72 | private: 73 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow) 74 | }; 75 | 76 | private: 77 | ScopedPointer mainWindow; 78 | }; 79 | 80 | //============================================================================== 81 | // This macro generates the main() routine that launches the app. 82 | START_JUCE_APPLICATION (OSCTimecodeApplication) 83 | -------------------------------------------------------------------------------- /Source/MainComponent.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | OSCTimecode - Juce OSC Timecode example application 3 | 4 | Copyright (C) 2017 Haute Technique - Sander ter Braak and Jan de Boer 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as 8 | published by the Free Software Foundation, either version 3 of the 9 | License, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library. 18 | 19 | If not, see . 20 | */ 21 | 22 | #include "MainComponent.h" 23 | 24 | TimeCodeTest MainContentComponent::test; 25 | 26 | MainContentComponent::MainContentComponent() 27 | { 28 | lookAndFeel = new CustomLookAndFeel(); 29 | LookAndFeel::setDefaultLookAndFeel(lookAndFeel); 30 | 31 | UnitTestRunner ur; 32 | ur.runAllTests(); 33 | 34 | active = false; 35 | sender = true; 36 | 37 | activeButton = new TextButton("Start"); 38 | activeButton->addListener(this); 39 | addAndMakeVisible(activeButton); 40 | 41 | 42 | modeLabel = new Label(); 43 | addAndMakeVisible(modeLabel); 44 | modeLabel->setJustificationType(Justification::centred); 45 | modeLabel->setText("Sender", dontSendNotification); 46 | 47 | 48 | senderButton = new TextButton("Sender"); 49 | senderButton->addListener(this); 50 | addAndMakeVisible(senderButton); 51 | 52 | 53 | ipEditor = new TextEditor(); 54 | ipEditor->setText("127.0.0.1"); 55 | addAndMakeVisible(ipEditor); 56 | 57 | portEditor = new TextEditor(); 58 | portEditor->setText("1337"); 59 | addAndMakeVisible(portEditor); 60 | 61 | fpsEditor = new TextEditor(); 62 | fpsEditor->setText("30"); 63 | addAndMakeVisible(fpsEditor); 64 | 65 | offsetEditor = new TextEditor(); 66 | offsetEditor->setText("00:00:00:00"); 67 | addAndMakeVisible(offsetEditor); 68 | 69 | timeLabel = new TimeLabel(); 70 | timeLabel->setText("--:--:--:--"); 71 | 72 | addAndMakeVisible(timeLabel); 73 | 74 | setSize (320, 300); 75 | } 76 | 77 | MainContentComponent::~MainContentComponent() 78 | { 79 | if(active) 80 | stop(); 81 | } 82 | 83 | void MainContentComponent::paint (Graphics& g) 84 | { 85 | const int spacing = 30; 86 | 87 | g.setColour(Colours::white); 88 | g.drawText("IP:", 15, 24, 80, 30, Justification::topRight); 89 | g.drawText("PORT:", 15, 24 + spacing, 80, 30, Justification::topRight); 90 | g.drawText("FPS:", 15, 24 + spacing * 2, 80, 30, Justification::topRight); 91 | g.drawText("OFFSET:", 15, 24 + spacing * 3, 80, 30, Justification::topRight); 92 | g.drawText("MODE:", 15, 24 + spacing * 4, 80, 30, Justification::topRight); 93 | } 94 | 95 | void MainContentComponent::resized() 96 | { 97 | Rectangle area = getLocalBounds(); 98 | Rectangle top = area.removeFromTop(area.getHeight()).reduced(15, 15); 99 | Rectangle topLeft = top.removeFromLeft(top.getWidth()).removeFromRight(210); 100 | 101 | ipEditor->setBounds(topLeft.removeFromTop(30).reduced(5, 5)); 102 | portEditor->setBounds(topLeft.removeFromTop(30).reduced(5, 5)); 103 | fpsEditor->setBounds(topLeft.removeFromTop(30).reduced(5, 5)); 104 | offsetEditor->setBounds(topLeft.removeFromTop(30).reduced(5, 5)); 105 | senderButton->setBounds(topLeft.removeFromTop(30).reduced(5, 5)); 106 | modeLabel->setBounds(senderButton->getBounds().reduced(5, 5)); 107 | activeButton->setBounds(topLeft.withRight(200).removeFromTop(30).reduced(5, 5)); 108 | timeLabel->setBounds(getLocalBounds().withTop(210).withHeight(60)); 109 | } 110 | 111 | void MainContentComponent::start() 112 | { 113 | 114 | validateFields(); 115 | 116 | framesPerSecond = fpsEditor->getText().getIntValue(); 117 | ip = ipEditor->getText(); 118 | port = portEditor->getText().getIntValue(); 119 | 120 | if(sender) 121 | { 122 | oscSender = new OSCSender(); 123 | if(!oscSender->connect(ip, port)) 124 | DBG("Unable to connect to " + ip + ":" + String(port)); 125 | 126 | currentTimeMillis = TimeCode(offsetEditor->getText(), framesPerSecond); 127 | 128 | startTimer(1000 / 60); 129 | 130 | lastUpdateMillis = Time::currentTimeMillis(); 131 | 132 | DBG("Sending"); 133 | } 134 | else 135 | { 136 | oscReceiver = new OSCReceiver(); 137 | oscReceiver->addListener(this); 138 | oscReceiver->connect(port); 139 | 140 | timeLabel->setText("--:--:--:--"); 141 | 142 | DBG("Listening on port: " + String(port)); 143 | } 144 | 145 | } 146 | 147 | void MainContentComponent::validateFields() 148 | { 149 | // IP 150 | const IPAddress ip(ipEditor->getText()); 151 | ipEditor->setText(ip.toString()); 152 | 153 | 154 | // port 155 | int port = portEditor->getText().getIntValue(); 156 | port = jmax(jmin(port, 65535), 1024); 157 | portEditor->setText(String(port)); 158 | 159 | // FPS 160 | int fps = fpsEditor->getText().getIntValue(); 161 | fps = jmax(jmin(fps, 1000), 1); 162 | fpsEditor->setText(String(fps)); 163 | 164 | // OFFSET 165 | const TimeCode currentOffset(offsetEditor->getText(), fps); 166 | 167 | offsetEditor->setText(currentOffset.toString(fps)); 168 | } 169 | 170 | void MainContentComponent::stop() 171 | { 172 | if(sender) 173 | { 174 | oscSender->disconnect(); 175 | stopTimer(); 176 | 177 | DBG("Stopped sending"); 178 | } 179 | else 180 | { 181 | oscReceiver->disconnect(); 182 | 183 | DBG("Stopped receiving"); 184 | } 185 | 186 | timeLabel->setText("--:--:--:--"); 187 | } 188 | 189 | void MainContentComponent::buttonClicked(Button *button) 190 | { 191 | if(button == activeButton) 192 | { 193 | if(active) 194 | stop(); 195 | else 196 | start(); 197 | 198 | active = !active; 199 | 200 | String buttonText = active ? "Stop" : "Start"; 201 | activeButton->setButtonText(buttonText); 202 | senderButton->setVisible(!active); 203 | } 204 | else if(button == senderButton) 205 | { 206 | if(!active) 207 | { 208 | sender = !sender; 209 | 210 | String buttonText = sender ? "Sender" : "Receiver"; 211 | senderButton->setButtonText(buttonText); 212 | modeLabel->setText(buttonText, dontSendNotification); 213 | } 214 | } 215 | 216 | const bool enabled = !active && sender; 217 | 218 | ipEditor->setEnabled(enabled); 219 | portEditor->setEnabled(!active); 220 | fpsEditor->setEnabled(enabled); 221 | offsetEditor->setEnabled(enabled); 222 | } 223 | 224 | void MainContentComponent::timerCallback() 225 | { 226 | const int64 diffInMillis = (Time::currentTimeMillis() - lastUpdateMillis); 227 | currentTimeMillis += diffInMillis; 228 | lastUpdateMillis = Time::currentTimeMillis(); 229 | 230 | const TimeCode currentTime(currentTimeMillis); 231 | 232 | String timeString = currentTime.toString(framesPerSecond); 233 | 234 | OSCMessage message("/TC1/time/" + String(framesPerSecond)); 235 | message.addString(timeString); 236 | 237 | if(!oscSender->send(message)) 238 | DBG("Unable to send"); 239 | 240 | timeLabel->setTimeCode(timeString); 241 | } 242 | 243 | void MainContentComponent::oscMessageReceived (const OSCMessage& message) 244 | { 245 | const OSCAddressPattern pattern("/TC*/time/*"); 246 | 247 | OSCAddressPattern messagePattern = message.getAddressPattern(); 248 | 249 | // Did we recieve an timecode message 250 | if(pattern.matches(messagePattern.toString())) 251 | { 252 | if(message.size() == 1) 253 | { 254 | const String timeString = message[0].getString(); 255 | timeLabel->setText(timeString); 256 | } 257 | else 258 | { 259 | DBG("Received invalid timecode message"); 260 | } 261 | } 262 | } 263 | 264 | 265 | 266 | 267 | 268 | -------------------------------------------------------------------------------- /Source/MainComponent.h: -------------------------------------------------------------------------------- 1 | /* 2 | OSCTimecode - Juce OSC Timecode example application 3 | 4 | Copyright (C) 2017 Haute Technique - Sander ter Braak and Jan de Boer 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as 8 | published by the Free Software Foundation, either version 3 of the 9 | License, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library. 18 | 19 | If not, see . 20 | */ 21 | 22 | #ifndef MAINCOMPONENT_H_INCLUDED 23 | #define MAINCOMPONENT_H_INCLUDED 24 | 25 | #include "../JuceLibraryCode/JuceHeader.h" 26 | 27 | #include "TimeLabel.hpp" 28 | #include "TimeCode.hpp" 29 | #include "LookAndFeel/CustomLookAndFeel.hpp" 30 | #include "TimeCodeTest.hpp" 31 | 32 | 33 | class MainContentComponent : public Component, 34 | public Button::Listener, 35 | public Timer, 36 | public OSCReceiver::Listener 37 | { 38 | public: 39 | 40 | MainContentComponent(); 41 | ~MainContentComponent(); 42 | 43 | 44 | static TimeCodeTest test; 45 | 46 | void paint (Graphics&) override; 47 | void resized() override; 48 | 49 | double framesPerSecond; 50 | 51 | int64 currentTimeMillis; 52 | 53 | int64 lastUpdateMillis; 54 | 55 | String ip; 56 | 57 | int port; 58 | 59 | bool sender; 60 | 61 | bool active; 62 | 63 | ScopedPointer oscSender; 64 | 65 | ScopedPointer oscReceiver; 66 | 67 | 68 | 69 | ScopedPointer activeButton; 70 | 71 | ScopedPointer senderButton; 72 | 73 | ScopedPointer timeLabel; 74 | 75 | ScopedPointer ipEditor; 76 | 77 | ScopedPointer portEditor; 78 | 79 | ScopedPointer fpsEditor; 80 | 81 | ScopedPointer offsetEditor; 82 | 83 | ScopedPointer