├── .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 | 
27 |
28 | *Receiver*
29 |
30 | 
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